Skip to content

Commit 8f6cf43

Browse files
committed
[Tests] Refactored parsing of scheme from repo URL, moved Array utils to Collection utils, added Collection tests, moved all allTests functions into one file, previously they were in FileTests which was hard to find
1 parent b354d67 commit 8f6cf43

File tree

8 files changed

+311
-164
lines changed

8 files changed

+311
-164
lines changed

Sources/Utility/ArrayExtensions.swift

Lines changed: 0 additions & 44 deletions
This file was deleted.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright 2015 - 2016 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
extension Collection {
12+
13+
public func pick(body: (Iterator.Element) -> Bool) -> Iterator.Element? {
14+
for x in self where body(x) {
15+
return x
16+
}
17+
return nil
18+
}
19+
20+
public func partition<T, U>() -> ([T], [U]) {
21+
var t = [T]()
22+
var u = [U]()
23+
for e in self {
24+
if let e = e as? T {
25+
t.append(e)
26+
} else if let e = e as? U {
27+
u.append(e)
28+
}
29+
}
30+
return (t, u)
31+
}
32+
33+
public func partition(body: (Iterator.Element) -> Bool) -> ([Iterator.Element], [Iterator.Element]) {
34+
var a: [Iterator.Element] = []
35+
var b: [Iterator.Element] = []
36+
for e in self {
37+
if body(e) {
38+
a.append(e)
39+
} else {
40+
b.append(e)
41+
}
42+
}
43+
return (a, b)
44+
}
45+
}
46+
47+
extension Collection where Iterator.Element : Equatable {
48+
49+
/// Split around a delimiting subsequence with maximum number of splits == 2
50+
func splitAround(delimiter: [Iterator.Element]) -> ([Iterator.Element], [Iterator.Element]?) {
51+
52+
let orig = Array(self)
53+
let end = orig.endIndex
54+
let delimCount = delimiter.count
55+
56+
var index = orig.startIndex
57+
while index+delimCount <= end {
58+
let cur = Array(orig[index..<index+delimCount])
59+
if cur == delimiter {
60+
//found
61+
let leading = Array(orig[0..<index])
62+
let trailing = Array(orig.suffix(orig.count-leading.count-delimCount))
63+
return (leading, trailing)
64+
} else {
65+
//not found, move index down
66+
index = index.successor()
67+
}
68+
}
69+
return (orig, nil)
70+
}
71+
}

Sources/Utility/StringExtensions.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,16 @@ extension String {
7070

7171
return String(cc)
7272
}
73+
74+
/// Splits string around a delimiter string into up to two substrings
75+
/// If delimiter is not found, the second returned substring is nil
76+
func splitAround(delimiter: String) -> (String, String?) {
77+
let comps = self.characters.splitAround(Array(delimiter.characters))
78+
let head = String(comps.0)
79+
if let tail = comps.1 {
80+
return (head, String(tail))
81+
} else {
82+
return (head, nil)
83+
}
84+
}
7385
}

Sources/Utility/URL.swift

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,30 @@
99
*/
1010

1111
public struct URL {
12+
13+
/// Parses the URL type of a git repository
14+
/// e.g. https://github.com/apple/swift returns "https"
15+
/// e.g. [email protected]:apple/swift returns "git"
16+
///
17+
/// This is *not* a generic URI scheme parser!
1218
public static func scheme(url: String) -> String? {
13-
// this is not fully RFC compliant, so it either has to be
14-
// or we need to use CFLite FIXME
1519

16-
let count = url.characters.count
17-
18-
func foo(start: Int) -> String? {
19-
guard count > start + 3 else { return nil }
20-
21-
let a = url.startIndex
22-
let b = a.advanced(by: start)
23-
let c = b.advanced(by: 3)
24-
if url[b..<c] == "://" || url[b] == "@" {
25-
return url[a..<b]
26-
} else {
20+
func prefixOfSplitBy(delimiter: String) -> String? {
21+
let (head, tail) = url.splitAround(delimiter)
22+
if tail == nil {
23+
//not found
2724
return nil
2825
}
26+
//found, return head
27+
//lowercase the "scheme", as specified by the URI RFC (just in case)
28+
return head.lowercased()
29+
}
30+
31+
for delim in ["://", "@"] {
32+
if let found = prefixOfSplitBy(delim) {
33+
return found
34+
}
2935
}
30-
return foo(4) ?? foo(5) ?? foo(3)
36+
return nil
3137
}
3238
}

Tests/Utility/CollectionTests.swift

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright 2015 - 2016 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
@testable import Utility
12+
import XCTest
13+
14+
class CollectionTests: XCTestCase {
15+
16+
func testPick() {
17+
18+
let body = { (num: Int) -> Bool in num > 5 }
19+
20+
XCTAssertNil([].pick(body))
21+
XCTAssertNil([3, 4].pick(body))
22+
XCTAssertEqual([3, 7].pick(body), 7)
23+
XCTAssertEqual([3, 8, 7].pick(body), 8)
24+
}
25+
26+
func testPartitionByType() {
27+
28+
let input0: [Any] = []
29+
let output0: ([String], [Int]) = input0.partition()
30+
XCTAssertEqual(output0.0, [String]())
31+
XCTAssertEqual(output0.1, [Int]())
32+
33+
let input1: [Any] = [1, "two", 3, "four"]
34+
let output1: ([String], [Int]) = input1.partition()
35+
XCTAssertEqual(output1.0, ["two", "four"])
36+
XCTAssertEqual(output1.1, [1, 3])
37+
}
38+
39+
func testPartitionByClosure() {
40+
41+
func eq(lhs: ([Int], [Int]), _ rhs: ([Int], [Int]), file: StaticString = #file, line: UInt = #line) {
42+
XCTAssertEqual(lhs.0, rhs.0, file: file, line: line)
43+
XCTAssertEqual(lhs.1, rhs.1, file: file, line: line)
44+
}
45+
46+
let body = { (num: Int) -> Bool in num > 5 }
47+
48+
eq([Int]().partition(body), ([], []))
49+
eq([2].partition(body), ([], [2]))
50+
eq([7].partition(body), ([7], []))
51+
eq([7, 4, 2, 9].partition(body), ([7, 9], [4, 2]))
52+
}
53+
54+
func testSplitAround() {
55+
56+
func eq(lhs: ([Character], [Character]?), _ rhs: ([Character], [Character]?), file: StaticString = #file, line: UInt = #line) {
57+
XCTAssertEqual(lhs.0, rhs.0, file: file, line: line)
58+
XCTAssertEqual(lhs.1 ?? [], rhs.1 ?? [], file: file, line: line)
59+
}
60+
61+
eq([].splitAround([":"]), ([], nil))
62+
eq(["f", "o", "o"].splitAround([":"]), (["f", "o", "o"], nil))
63+
eq(["f", "o", "o", ":"].splitAround([":"]), (["f", "o", "o"], []))
64+
eq([":", "b", "a", "r"].splitAround([":"]), ([], ["b", "a", "r"]))
65+
eq(["f", "o", "o", ":", "b", "a", "r"].splitAround([":"]), (["f", "o", "o"], ["b", "a", "r"]))
66+
67+
}
68+
}

Tests/Utility/FileTests.swift

Lines changed: 0 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -67,102 +67,3 @@ class FileTests: XCTestCase {
6767
}
6868
}
6969
}
70-
71-
72-
extension FileTests {
73-
static var allTests : [(String, FileTests -> () throws -> Void)] {
74-
return [
75-
("testOpenFile", testOpenFile),
76-
("testOpenFileFail", testOpenFileFail),
77-
("testReadRegularTextFile", testReadRegularTextFile),
78-
("testReadRegularTextFileWithSeparator", testReadRegularTextFileWithSeparator)
79-
]
80-
}
81-
}
82-
83-
84-
extension RmtreeTests {
85-
static var allTests : [(String, RmtreeTests -> () throws -> Void)] {
86-
return [
87-
("testDoesNotFollowSymlinks", testDoesNotFollowSymlinks),
88-
]
89-
}
90-
}
91-
92-
extension PathTests {
93-
static var allTests : [(String, PathTests -> () throws -> Void)] {
94-
return [
95-
("test", test),
96-
("testPrecombined", testPrecombined),
97-
("testExtraSeparators", testExtraSeparators),
98-
("testEmpties", testEmpties),
99-
("testNormalizePath", testNormalizePath),
100-
("testJoinWithAbsoluteReturnsLastAbsoluteComponent", testJoinWithAbsoluteReturnsLastAbsoluteComponent),
101-
("testParentDirectory", testParentDirectory),
102-
]
103-
}
104-
}
105-
106-
extension WalkTests {
107-
static var allTests : [(String, WalkTests -> () throws -> Void)] {
108-
return [
109-
("testNonRecursive", testNonRecursive),
110-
("testRecursive", testRecursive),
111-
("testSymlinksNotWalked", testSymlinksNotWalked),
112-
("testWalkingADirectorySymlinkResolvesOnce", testWalkingADirectorySymlinkResolvesOnce),
113-
]
114-
}
115-
}
116-
117-
extension StatTests {
118-
static var allTests : [(String, StatTests -> () throws -> Void)] {
119-
return [
120-
("test_isdir", test_isdir),
121-
("test_isfile", test_isfile),
122-
("test_realpath", test_realpath),
123-
("test_basename", test_basename),
124-
]
125-
}
126-
}
127-
128-
extension RelativePathTests {
129-
static var allTests : [(String, RelativePathTests -> () throws -> Void)] {
130-
return [
131-
("testAbsolute", testAbsolute),
132-
("testRelative", testRelative),
133-
("testMixed", testMixed),
134-
("testRelativeCommonSubprefix", testRelativeCommonSubprefix)
135-
]
136-
}
137-
}
138-
139-
extension ShellTests {
140-
static var allTests : [(String, ShellTests -> () throws -> Void)] {
141-
return [
142-
("testPopen", testPopen),
143-
("testPopenWithBufferLargerThanThatAllocated", testPopenWithBufferLargerThanThatAllocated),
144-
("testPopenWithBinaryOutput", testPopenWithBinaryOutput)
145-
]
146-
}
147-
}
148-
149-
150-
extension StringTests {
151-
static var allTests : [(String, StringTests -> () throws -> Void)] {
152-
return [
153-
("testTrailingChomp", testTrailingChomp),
154-
("testEmptyChomp", testEmptyChomp),
155-
("testSeparatorChomp", testSeparatorChomp),
156-
("testChuzzle", testChuzzle),
157-
]
158-
}
159-
160-
}
161-
162-
extension URLTests {
163-
static var allTests : [(String, URLTests -> () throws -> Void)] {
164-
return [
165-
("testSchema", testSchema),
166-
]
167-
}
168-
}

Tests/Utility/StringTests.swift

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,31 @@ class StringTests: XCTestCase {
4242
XCTAssertEqual(" a\t\r\n".chuzzle(), "a")
4343
XCTAssertEqual("b".chuzzle(), "b")
4444
}
45+
46+
func testSplitAround() {
47+
48+
func eq(lhs: (String, String?), _ rhs: (String, String?), file: StaticString = #file, line: UInt = #line) {
49+
XCTAssertEqual(lhs.0, rhs.0, file: file, line: line)
50+
XCTAssertEqual(lhs.1, rhs.1, file: file, line: line)
51+
}
52+
53+
eq("".splitAround("::"), ("", nil))
54+
eq("foo".splitAround("::"), ("foo", nil))
55+
eq("foo::".splitAround("::"), ("foo", ""))
56+
eq("::bar".splitAround("::"), ("", "bar"))
57+
eq("foo::bar".splitAround("::"), ("foo", "bar"))
58+
}
4559
}
4660

47-
4861
class URLTests: XCTestCase {
4962

5063
func testSchema() {
51-
let a = "http://github.com/foo/bar"
52-
let b = "https://github.com/foo/bar"
53-
let c = "[email protected]/foo/bar"
54-
XCTAssertEqual(Utility.URL.scheme(a), "http")
55-
XCTAssertEqual(Utility.URL.scheme(b), "https")
56-
XCTAssertEqual(Utility.URL.scheme(c), "git")
64+
XCTAssertEqual(Utility.URL.scheme("http://github.com/foo/bar"), "http")
65+
XCTAssertEqual(Utility.URL.scheme("https://github.com/foo/bar"), "https")
66+
XCTAssertEqual(Utility.URL.scheme("HTTPS://github.com/foo/bar"), "https")
67+
XCTAssertEqual(Utility.URL.scheme("[email protected]/foo/bar"), "git")
68+
XCTAssertEqual(Utility.URL.scheme("[email protected]/foo/bar"), "ssh")
69+
XCTAssertNil(Utility.URL.scheme("github.com/foo/bar"))
70+
XCTAssertNil(Utility.URL.scheme("user:/github.com/foo/bar"))
5771
}
5872
}

0 commit comments

Comments
 (0)