|
|
|
|
@@ -680,308 +680,307 @@ extension StringParser {
|
|
|
|
|
// Unit Tests
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
|
|
extension SmallProjectionPath {
|
|
|
|
|
public static func runUnitTests() {
|
|
|
|
|
|
|
|
|
|
basicPushPop()
|
|
|
|
|
parsing()
|
|
|
|
|
merging()
|
|
|
|
|
subtracting()
|
|
|
|
|
matching()
|
|
|
|
|
overlapping()
|
|
|
|
|
predicates()
|
|
|
|
|
path2path()
|
|
|
|
|
indexedElements()
|
|
|
|
|
let smallProjectionPathTest = Test("small_projection_path") {
|
|
|
|
|
function, arguments, context in
|
|
|
|
|
|
|
|
|
|
func basicPushPop() {
|
|
|
|
|
let p1 = SmallProjectionPath(.structField, index: 3)
|
|
|
|
|
.push(.classField, index: 12345678)
|
|
|
|
|
let (k2, i2, p2) = p1.pop()
|
|
|
|
|
assert(k2 == .classField && i2 == 12345678)
|
|
|
|
|
let (k3, i3, p3) = p2.pop()
|
|
|
|
|
assert(k3 == .structField && i3 == 3)
|
|
|
|
|
assert(p3.isEmpty)
|
|
|
|
|
let (k4, i4, _) = p2.push(.enumCase, index: 876).pop()
|
|
|
|
|
assert(k4 == .enumCase && i4 == 876)
|
|
|
|
|
let p5 = SmallProjectionPath(.anything)
|
|
|
|
|
assert(p5.pop().path.isEmpty)
|
|
|
|
|
let p6 = SmallProjectionPath(.indexedElement, index: 1).push(.indexedElement, index: 2)
|
|
|
|
|
let (k6, i6, p7) = p6.pop()
|
|
|
|
|
assert(k6 == .indexedElement && i6 == 3 && p7.isEmpty)
|
|
|
|
|
let p8 = SmallProjectionPath(.indexedElement, index: 0)
|
|
|
|
|
assert(p8.isEmpty)
|
|
|
|
|
let p9 = SmallProjectionPath(.indexedElement, index: 1).push(.anyIndexedElement)
|
|
|
|
|
let (k9, i9, p10) = p9.pop()
|
|
|
|
|
assert(k9 == .anyIndexedElement && i9 == 0 && p10.isEmpty)
|
|
|
|
|
let p11 = SmallProjectionPath(.anyIndexedElement).push(.indexedElement, index: 1)
|
|
|
|
|
let (k11, i11, p12) = p11.pop()
|
|
|
|
|
assert(k11 == .anyIndexedElement && i11 == 0 && p12.isEmpty)
|
|
|
|
|
basicPushPop()
|
|
|
|
|
parsing()
|
|
|
|
|
merging()
|
|
|
|
|
subtracting()
|
|
|
|
|
matching()
|
|
|
|
|
overlapping()
|
|
|
|
|
predicates()
|
|
|
|
|
path2path()
|
|
|
|
|
indexedElements()
|
|
|
|
|
|
|
|
|
|
func basicPushPop() {
|
|
|
|
|
let p1 = SmallProjectionPath(.structField, index: 3)
|
|
|
|
|
.push(.classField, index: 12345678)
|
|
|
|
|
let (k2, i2, p2) = p1.pop()
|
|
|
|
|
assert(k2 == .classField && i2 == 12345678)
|
|
|
|
|
let (k3, i3, p3) = p2.pop()
|
|
|
|
|
assert(k3 == .structField && i3 == 3)
|
|
|
|
|
assert(p3.isEmpty)
|
|
|
|
|
let (k4, i4, _) = p2.push(.enumCase, index: 876).pop()
|
|
|
|
|
assert(k4 == .enumCase && i4 == 876)
|
|
|
|
|
let p5 = SmallProjectionPath(.anything)
|
|
|
|
|
assert(p5.pop().path.isEmpty)
|
|
|
|
|
let p6 = SmallProjectionPath(.indexedElement, index: 1).push(.indexedElement, index: 2)
|
|
|
|
|
let (k6, i6, p7) = p6.pop()
|
|
|
|
|
assert(k6 == .indexedElement && i6 == 3 && p7.isEmpty)
|
|
|
|
|
let p8 = SmallProjectionPath(.indexedElement, index: 0)
|
|
|
|
|
assert(p8.isEmpty)
|
|
|
|
|
let p9 = SmallProjectionPath(.indexedElement, index: 1).push(.anyIndexedElement)
|
|
|
|
|
let (k9, i9, p10) = p9.pop()
|
|
|
|
|
assert(k9 == .anyIndexedElement && i9 == 0 && p10.isEmpty)
|
|
|
|
|
let p11 = SmallProjectionPath(.anyIndexedElement).push(.indexedElement, index: 1)
|
|
|
|
|
let (k11, i11, p12) = p11.pop()
|
|
|
|
|
assert(k11 == .anyIndexedElement && i11 == 0 && p12.isEmpty)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parsing() {
|
|
|
|
|
testParse("v**.c*", expect: SmallProjectionPath(.anyClassField)
|
|
|
|
|
.push(.anyValueFields))
|
|
|
|
|
testParse("s3.c*.v**.s1", expect: SmallProjectionPath(.structField, index: 1)
|
|
|
|
|
.push(.anyValueFields)
|
|
|
|
|
.push(.anyClassField)
|
|
|
|
|
.push(.structField, index: 3))
|
|
|
|
|
testParse("2.c*.e6.ct.**", expect: SmallProjectionPath(.anything)
|
|
|
|
|
.push(.tailElements)
|
|
|
|
|
.push(.enumCase, index: 6)
|
|
|
|
|
.push(.anyClassField)
|
|
|
|
|
.push(.tupleField, index: 2))
|
|
|
|
|
testParse("i3.x.b.i*", expect: SmallProjectionPath(.anyIndexedElement)
|
|
|
|
|
.push(.vectorBase)
|
|
|
|
|
.push(.existential)
|
|
|
|
|
.push(.indexedElement, index: 3))
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
var parser = StringParser("c*.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.**")
|
|
|
|
|
_ = try parser.parseProjectionPathFromSIL()
|
|
|
|
|
fatalError("too long path not detected")
|
|
|
|
|
} catch {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parsing() {
|
|
|
|
|
testParse("v**.c*", expect: SmallProjectionPath(.anyClassField)
|
|
|
|
|
.push(.anyValueFields))
|
|
|
|
|
testParse("s3.c*.v**.s1", expect: SmallProjectionPath(.structField, index: 1)
|
|
|
|
|
.push(.anyValueFields)
|
|
|
|
|
.push(.anyClassField)
|
|
|
|
|
.push(.structField, index: 3))
|
|
|
|
|
testParse("2.c*.e6.ct.**", expect: SmallProjectionPath(.anything)
|
|
|
|
|
.push(.tailElements)
|
|
|
|
|
.push(.enumCase, index: 6)
|
|
|
|
|
.push(.anyClassField)
|
|
|
|
|
.push(.tupleField, index: 2))
|
|
|
|
|
testParse("i3.x.b.i*", expect: SmallProjectionPath(.anyIndexedElement)
|
|
|
|
|
.push(.vectorBase)
|
|
|
|
|
.push(.existential)
|
|
|
|
|
.push(.indexedElement, index: 3))
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
var parser = StringParser("c*.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.s123.s3.**")
|
|
|
|
|
_ = try parser.parseProjectionPathFromSIL()
|
|
|
|
|
fatalError("too long path not detected")
|
|
|
|
|
} catch {
|
|
|
|
|
}
|
|
|
|
|
do {
|
|
|
|
|
var parser = StringParser("**.s0")
|
|
|
|
|
_ = try parser.parseProjectionPathFromSIL()
|
|
|
|
|
fatalError("wrong '**' not detected")
|
|
|
|
|
} catch {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testParse(_ pathStr: String, expect: SmallProjectionPath) {
|
|
|
|
|
var parser = StringParser(pathStr)
|
|
|
|
|
let path = try! parser.parseProjectionPathFromSIL()
|
|
|
|
|
assert(path == expect)
|
|
|
|
|
let str = path.description
|
|
|
|
|
assert(str == pathStr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func merging() {
|
|
|
|
|
testMerge("c1.c0", "c0", expect: "c*.**")
|
|
|
|
|
testMerge("c2.c1", "c2", expect: "c2.**")
|
|
|
|
|
testMerge("s3.c0", "v**.c0", expect: "v**.c0")
|
|
|
|
|
testMerge("c0", "s2.c1", expect: "v**.c*")
|
|
|
|
|
testMerge("s1.s1.c2", "s1.c2", expect: "s1.v**.c2")
|
|
|
|
|
testMerge("s1.s0", "s2.s0", expect: "v**")
|
|
|
|
|
testMerge("ct", "c2", expect: "c*")
|
|
|
|
|
testMerge("i1", "i2", expect: "i*")
|
|
|
|
|
testMerge("i*", "i2", expect: "i*")
|
|
|
|
|
testMerge("s0.i*.e3", "s0.e3", expect: "s0.i*.e3")
|
|
|
|
|
testMerge("i*", "v**", expect: "v**")
|
|
|
|
|
testMerge("s0.b.i1", "s0.b.i0", expect: "s0.b.i*")
|
|
|
|
|
testMerge("s0.b", "s0.1", expect: "s0.v**")
|
|
|
|
|
|
|
|
|
|
testMerge("ct.s0.e0.v**.c0", "ct.s0.e0.v**.c0", expect: "ct.s0.e0.v**.c0")
|
|
|
|
|
testMerge("ct.s0.s0.c0", "ct.s0.e0.s0.c0", expect: "ct.s0.v**.c0")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testMerge(_ lhsStr: String, _ rhsStr: String,
|
|
|
|
|
expect expectStr: String) {
|
|
|
|
|
var lhsParser = StringParser(lhsStr)
|
|
|
|
|
let lhs = try! lhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
var rhsParser = StringParser(rhsStr)
|
|
|
|
|
let rhs = try! rhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
var expectParser = StringParser(expectStr)
|
|
|
|
|
let expect = try! expectParser.parseProjectionPathFromSIL()
|
|
|
|
|
|
|
|
|
|
let result = lhs.merge(with: rhs)
|
|
|
|
|
assert(result == expect)
|
|
|
|
|
let result2 = rhs.merge(with: lhs)
|
|
|
|
|
assert(result2 == expect)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func subtracting() {
|
|
|
|
|
testSubtract("s0", "s0.s1", expect: "s1")
|
|
|
|
|
testSubtract("s0", "s1", expect: nil)
|
|
|
|
|
testSubtract("s0.s1", "s0.s1", expect: "")
|
|
|
|
|
testSubtract("i*.s1", "i*.s1", expect: nil)
|
|
|
|
|
testSubtract("ct.s1.0.i3.x", "ct.s1.0.i3.x", expect: "")
|
|
|
|
|
testSubtract("c0.s1.0.i3", "c0.s1.0.i3.x", expect: "x")
|
|
|
|
|
testSubtract("s1.0.i3.x", "s1.0.i3", expect: nil)
|
|
|
|
|
testSubtract("v**.s1", "v**.s1", expect: nil)
|
|
|
|
|
testSubtract("i*", "i*", expect: nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testSubtract(_ lhsStr: String, _ rhsStr: String, expect expectStr: String?) {
|
|
|
|
|
var lhsParser = StringParser(lhsStr)
|
|
|
|
|
let lhs = try! lhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
var rhsParser = StringParser(rhsStr)
|
|
|
|
|
let rhs = try! rhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
|
|
|
|
|
let result = lhs.subtract(from: rhs)
|
|
|
|
|
|
|
|
|
|
if let expectStr = expectStr {
|
|
|
|
|
var expectParser = StringParser(expectStr)
|
|
|
|
|
let expect = try! expectParser.parseProjectionPathFromSIL()
|
|
|
|
|
assert(result! == expect)
|
|
|
|
|
} else {
|
|
|
|
|
assert(result == nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func matching() {
|
|
|
|
|
testMatch("ct", "c*", expect: true)
|
|
|
|
|
testMatch("c1", "c*", expect: true)
|
|
|
|
|
testMatch("s2", "v**", expect: true)
|
|
|
|
|
testMatch("1", "v**", expect: true)
|
|
|
|
|
testMatch("e1", "v**", expect: true)
|
|
|
|
|
testMatch("c*", "c1", expect: false)
|
|
|
|
|
testMatch("c*", "ct", expect: false)
|
|
|
|
|
testMatch("v**", "s0", expect: false)
|
|
|
|
|
testMatch("i1", "i1", expect: true)
|
|
|
|
|
testMatch("i1", "i*", expect: true)
|
|
|
|
|
testMatch("i*", "i1", expect: false)
|
|
|
|
|
|
|
|
|
|
testMatch("s0.s1", "s0.s1", expect: true)
|
|
|
|
|
testMatch("s0.s2", "s0.s1", expect: false)
|
|
|
|
|
testMatch("s0", "s0.v**", expect: true)
|
|
|
|
|
testMatch("s0.s1", "s0.v**", expect: true)
|
|
|
|
|
testMatch("s0.1.e2", "s0.v**", expect: true)
|
|
|
|
|
testMatch("s0.v**.x.e2", "v**", expect: true)
|
|
|
|
|
testMatch("s0.v**", "s0.s1", expect: false)
|
|
|
|
|
testMatch("s0.s1.c*", "s0.v**", expect: false)
|
|
|
|
|
testMatch("s0.v**", "s0.**", expect: true)
|
|
|
|
|
testMatch("s1.v**", "s0.**", expect: false)
|
|
|
|
|
testMatch("s0.**", "s0.v**", expect: false)
|
|
|
|
|
testMatch("s0.s1", "s0.i*.s1", expect: true)
|
|
|
|
|
testMatch("s0.b.s1", "s0.b.i*.s1", expect: true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testMatch(_ lhsStr: String, _ rhsStr: String, expect: Bool) {
|
|
|
|
|
var lhsParser = StringParser(lhsStr)
|
|
|
|
|
let lhs = try! lhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
var rhsParser = StringParser(rhsStr)
|
|
|
|
|
let rhs = try! rhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
let result = lhs.matches(pattern: rhs)
|
|
|
|
|
assert(result == expect)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func overlapping() {
|
|
|
|
|
testOverlap("s0.s1.s2", "s0.s1.s2", expect: true)
|
|
|
|
|
testOverlap("s0.s1.s2", "s0.s2.s2", expect: false)
|
|
|
|
|
testOverlap("s0.s1.s2", "s0.e1.s2", expect: false)
|
|
|
|
|
testOverlap("s0.s1.s2", "s0.s1", expect: true)
|
|
|
|
|
testOverlap("s0.s1.s2", "s1.s2", expect: false)
|
|
|
|
|
|
|
|
|
|
testOverlap("s0.c*.s2", "s0.ct.s2", expect: true)
|
|
|
|
|
testOverlap("s0.c*.s2", "s0.c1.s2", expect: true)
|
|
|
|
|
testOverlap("s0.c*.s2", "s0.c1.c2.s2", expect: false)
|
|
|
|
|
testOverlap("s0.c*.s2", "s0.s2", expect: false)
|
|
|
|
|
|
|
|
|
|
testOverlap("s0.v**.s2", "s0.s3.x", expect: true)
|
|
|
|
|
testOverlap("s0.v**.s2.c2", "s0.s3.c1", expect: false)
|
|
|
|
|
testOverlap("s0.v**.s2", "s1.s3", expect: false)
|
|
|
|
|
testOverlap("s0.v**.s2", "s0.v**.s3", expect: true)
|
|
|
|
|
|
|
|
|
|
testOverlap("s0.**", "s0.s3.c1", expect: true)
|
|
|
|
|
testOverlap("**", "s0.s3.c1", expect: true)
|
|
|
|
|
|
|
|
|
|
testOverlap("i1", "i*", expect: true)
|
|
|
|
|
testOverlap("i1", "v**", expect: true)
|
|
|
|
|
testOverlap("s0.i*.s1", "s0.s1", expect: true)
|
|
|
|
|
testOverlap("s0.b.s1", "s0.b.i*.s1", expect: true)
|
|
|
|
|
testOverlap("s0.b.i0.s1", "s0.b.i1.s1", expect: false)
|
|
|
|
|
testOverlap("s0.b.i2.s1", "s0.b.i1.s1", expect: false)
|
|
|
|
|
testOverlap("s0.b.s1", "s0.b.i0.s1", expect: true)
|
|
|
|
|
testOverlap("s0.b", "s0.b.i1", expect: false)
|
|
|
|
|
testOverlap("s0.b.i1", "s0.b", expect: false)
|
|
|
|
|
testOverlap("s0.b.i1", "s0", expect: true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testOverlap(_ lhsStr: String, _ rhsStr: String, expect: Bool) {
|
|
|
|
|
var lhsParser = StringParser(lhsStr)
|
|
|
|
|
let lhs = try! lhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
var rhsParser = StringParser(rhsStr)
|
|
|
|
|
let rhs = try! rhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
let result = lhs.mayOverlap(with: rhs)
|
|
|
|
|
assert(result == expect)
|
|
|
|
|
let reversedResult = rhs.mayOverlap(with: lhs)
|
|
|
|
|
assert(reversedResult == expect)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func predicates() {
|
|
|
|
|
testPredicate("v**", \.hasClassProjection, expect: false)
|
|
|
|
|
testPredicate("v**.c0.s1.v**", \.hasClassProjection, expect: true)
|
|
|
|
|
testPredicate("c0.**", \.hasClassProjection, expect: true)
|
|
|
|
|
testPredicate("c0.c1", \.hasClassProjection, expect: true)
|
|
|
|
|
testPredicate("ct", \.hasClassProjection, expect: true)
|
|
|
|
|
testPredicate("s0", \.hasClassProjection, expect: false)
|
|
|
|
|
|
|
|
|
|
testPredicate("v**", \.mayHaveClassProjection, expect: false)
|
|
|
|
|
testPredicate("c0", \.mayHaveClassProjection, expect: true)
|
|
|
|
|
testPredicate("1", \.mayHaveClassProjection, expect: false)
|
|
|
|
|
testPredicate("**", \.mayHaveClassProjection, expect: true)
|
|
|
|
|
|
|
|
|
|
testPredicate("v**", \.mayHaveTwoClassProjections, expect: false)
|
|
|
|
|
testPredicate("c0", \.mayHaveTwoClassProjections, expect: false)
|
|
|
|
|
testPredicate("**", \.mayHaveTwoClassProjections, expect: true)
|
|
|
|
|
testPredicate("v**.c*.s2.1.c0", \.mayHaveTwoClassProjections, expect: true)
|
|
|
|
|
testPredicate("c*.s2.1.c0.v**", \.mayHaveTwoClassProjections, expect: true)
|
|
|
|
|
testPredicate("v**.c*.**", \.mayHaveTwoClassProjections, expect: true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testPredicate(_ pathStr: String, _ property: (SmallProjectionPath) -> Bool, expect: Bool) {
|
|
|
|
|
var parser = StringParser(pathStr)
|
|
|
|
|
let path = try! parser.parseProjectionPathFromSIL()
|
|
|
|
|
let result = property(path)
|
|
|
|
|
assert(result == expect)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func path2path() {
|
|
|
|
|
testPath2Path("s0.b.e2.3.c4.s1", { $0.popAllValueFields() }, expect: "c4.s1")
|
|
|
|
|
testPath2Path("v**.c4.s1", { $0.popAllValueFields() }, expect: "c4.s1")
|
|
|
|
|
testPath2Path("**", { $0.popAllValueFields() }, expect: "**")
|
|
|
|
|
|
|
|
|
|
testPath2Path("s0.e2.3.c4.s1.e2.v**.**", { $0.popLastClassAndValuesFromTail() }, expect: "s0.e2.3.c4.s1.e2.v**.**")
|
|
|
|
|
testPath2Path("s0.c2.3.c4.s1", { $0.popLastClassAndValuesFromTail() }, expect: "s0.c2.3")
|
|
|
|
|
testPath2Path("v**.c*.s1", { $0.popLastClassAndValuesFromTail() }, expect: "v**")
|
|
|
|
|
testPath2Path("s1.ct.v**", { $0.popLastClassAndValuesFromTail() }, expect: "s1")
|
|
|
|
|
testPath2Path("c0.c1.c2", { $0.popLastClassAndValuesFromTail() }, expect: "c0.c1")
|
|
|
|
|
testPath2Path("**", { $0.popLastClassAndValuesFromTail() }, expect: "**")
|
|
|
|
|
|
|
|
|
|
testPath2Path("v**.c3", { $0.popIfMatches(.anyValueFields) }, expect: "v**.c3")
|
|
|
|
|
testPath2Path("**", { $0.popIfMatches(.anyValueFields) }, expect: "**")
|
|
|
|
|
testPath2Path("s0.c3", { $0.popIfMatches(.anyValueFields) }, expect: nil)
|
|
|
|
|
|
|
|
|
|
testPath2Path("c0.s3", { $0.popIfMatches(.anyClassField) }, expect: nil)
|
|
|
|
|
testPath2Path("**", { $0.popIfMatches(.anyClassField) }, expect: "**")
|
|
|
|
|
testPath2Path("c*.e3", { $0.popIfMatches(.anyClassField) }, expect: "e3")
|
|
|
|
|
|
|
|
|
|
testPath2Path("i*.e3.s0", { $0.popIfMatches(.enumCase, index: 3) }, expect: "s0")
|
|
|
|
|
testPath2Path("i1.e3.s0", { $0.popIfMatches(.enumCase, index: 3) }, expect: nil)
|
|
|
|
|
testPath2Path("i*.e3.s0", { $0.popIfMatches(.indexedElement, index: 0) }, expect: "i*.e3.s0")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testPath2Path(_ pathStr: String, _ transform: (SmallProjectionPath) -> SmallProjectionPath?, expect: String?) {
|
|
|
|
|
var parser = StringParser(pathStr)
|
|
|
|
|
let path = try! parser.parseProjectionPathFromSIL()
|
|
|
|
|
let result = transform(path)
|
|
|
|
|
if let expect = expect {
|
|
|
|
|
var expectParser = StringParser(expect)
|
|
|
|
|
let expectPath = try! expectParser.parseProjectionPathFromSIL()
|
|
|
|
|
assert(result == expectPath)
|
|
|
|
|
} else {
|
|
|
|
|
assert(result == nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func indexedElements() {
|
|
|
|
|
let p1 = SmallProjectionPath(.indexedElement, index: 1)
|
|
|
|
|
let (k1, i1, s1) = p1.pop()
|
|
|
|
|
assert(k1 == .indexedElement && i1 == 1 && s1.isEmpty)
|
|
|
|
|
|
|
|
|
|
let p2 = SmallProjectionPath(.indexedElement, index: -1)
|
|
|
|
|
let (k2, _, s2) = p2.pop()
|
|
|
|
|
assert(k2 == .anything && s2.isEmpty)
|
|
|
|
|
|
|
|
|
|
let p3 = SmallProjectionPath(.indexedElement, index: 0xfffffffffffff)
|
|
|
|
|
let (k3, i3, s3) = p3.pop()
|
|
|
|
|
assert(k3 == .indexedElement && i3 == 0xfffffffffffff && s3.isEmpty)
|
|
|
|
|
|
|
|
|
|
let p4 = p3.push(.indexedElement, index: Int.max)
|
|
|
|
|
let (k4, _, s4) = p4.pop()
|
|
|
|
|
assert(k4 == .anyIndexedElement && s4.isEmpty)
|
|
|
|
|
do {
|
|
|
|
|
var parser = StringParser("**.s0")
|
|
|
|
|
_ = try parser.parseProjectionPathFromSIL()
|
|
|
|
|
fatalError("wrong '**' not detected")
|
|
|
|
|
} catch {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testParse(_ pathStr: String, expect: SmallProjectionPath) {
|
|
|
|
|
var parser = StringParser(pathStr)
|
|
|
|
|
let path = try! parser.parseProjectionPathFromSIL()
|
|
|
|
|
assert(path == expect)
|
|
|
|
|
let str = path.description
|
|
|
|
|
assert(str == pathStr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func merging() {
|
|
|
|
|
testMerge("c1.c0", "c0", expect: "c*.**")
|
|
|
|
|
testMerge("c2.c1", "c2", expect: "c2.**")
|
|
|
|
|
testMerge("s3.c0", "v**.c0", expect: "v**.c0")
|
|
|
|
|
testMerge("c0", "s2.c1", expect: "v**.c*")
|
|
|
|
|
testMerge("s1.s1.c2", "s1.c2", expect: "s1.v**.c2")
|
|
|
|
|
testMerge("s1.s0", "s2.s0", expect: "v**")
|
|
|
|
|
testMerge("ct", "c2", expect: "c*")
|
|
|
|
|
testMerge("i1", "i2", expect: "i*")
|
|
|
|
|
testMerge("i*", "i2", expect: "i*")
|
|
|
|
|
testMerge("s0.i*.e3", "s0.e3", expect: "s0.i*.e3")
|
|
|
|
|
testMerge("i*", "v**", expect: "v**")
|
|
|
|
|
testMerge("s0.b.i1", "s0.b.i0", expect: "s0.b.i*")
|
|
|
|
|
testMerge("s0.b", "s0.1", expect: "s0.v**")
|
|
|
|
|
|
|
|
|
|
testMerge("ct.s0.e0.v**.c0", "ct.s0.e0.v**.c0", expect: "ct.s0.e0.v**.c0")
|
|
|
|
|
testMerge("ct.s0.s0.c0", "ct.s0.e0.s0.c0", expect: "ct.s0.v**.c0")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testMerge(_ lhsStr: String, _ rhsStr: String,
|
|
|
|
|
expect expectStr: String) {
|
|
|
|
|
var lhsParser = StringParser(lhsStr)
|
|
|
|
|
let lhs = try! lhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
var rhsParser = StringParser(rhsStr)
|
|
|
|
|
let rhs = try! rhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
var expectParser = StringParser(expectStr)
|
|
|
|
|
let expect = try! expectParser.parseProjectionPathFromSIL()
|
|
|
|
|
|
|
|
|
|
let result = lhs.merge(with: rhs)
|
|
|
|
|
assert(result == expect)
|
|
|
|
|
let result2 = rhs.merge(with: lhs)
|
|
|
|
|
assert(result2 == expect)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func subtracting() {
|
|
|
|
|
testSubtract("s0", "s0.s1", expect: "s1")
|
|
|
|
|
testSubtract("s0", "s1", expect: nil)
|
|
|
|
|
testSubtract("s0.s1", "s0.s1", expect: "")
|
|
|
|
|
testSubtract("i*.s1", "i*.s1", expect: nil)
|
|
|
|
|
testSubtract("ct.s1.0.i3.x", "ct.s1.0.i3.x", expect: "")
|
|
|
|
|
testSubtract("c0.s1.0.i3", "c0.s1.0.i3.x", expect: "x")
|
|
|
|
|
testSubtract("s1.0.i3.x", "s1.0.i3", expect: nil)
|
|
|
|
|
testSubtract("v**.s1", "v**.s1", expect: nil)
|
|
|
|
|
testSubtract("i*", "i*", expect: nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testSubtract(_ lhsStr: String, _ rhsStr: String, expect expectStr: String?) {
|
|
|
|
|
var lhsParser = StringParser(lhsStr)
|
|
|
|
|
let lhs = try! lhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
var rhsParser = StringParser(rhsStr)
|
|
|
|
|
let rhs = try! rhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
|
|
|
|
|
let result = lhs.subtract(from: rhs)
|
|
|
|
|
|
|
|
|
|
if let expectStr = expectStr {
|
|
|
|
|
var expectParser = StringParser(expectStr)
|
|
|
|
|
let expect = try! expectParser.parseProjectionPathFromSIL()
|
|
|
|
|
assert(result! == expect)
|
|
|
|
|
} else {
|
|
|
|
|
assert(result == nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func matching() {
|
|
|
|
|
testMatch("ct", "c*", expect: true)
|
|
|
|
|
testMatch("c1", "c*", expect: true)
|
|
|
|
|
testMatch("s2", "v**", expect: true)
|
|
|
|
|
testMatch("1", "v**", expect: true)
|
|
|
|
|
testMatch("e1", "v**", expect: true)
|
|
|
|
|
testMatch("c*", "c1", expect: false)
|
|
|
|
|
testMatch("c*", "ct", expect: false)
|
|
|
|
|
testMatch("v**", "s0", expect: false)
|
|
|
|
|
testMatch("i1", "i1", expect: true)
|
|
|
|
|
testMatch("i1", "i*", expect: true)
|
|
|
|
|
testMatch("i*", "i1", expect: false)
|
|
|
|
|
|
|
|
|
|
testMatch("s0.s1", "s0.s1", expect: true)
|
|
|
|
|
testMatch("s0.s2", "s0.s1", expect: false)
|
|
|
|
|
testMatch("s0", "s0.v**", expect: true)
|
|
|
|
|
testMatch("s0.s1", "s0.v**", expect: true)
|
|
|
|
|
testMatch("s0.1.e2", "s0.v**", expect: true)
|
|
|
|
|
testMatch("s0.v**.x.e2", "v**", expect: true)
|
|
|
|
|
testMatch("s0.v**", "s0.s1", expect: false)
|
|
|
|
|
testMatch("s0.s1.c*", "s0.v**", expect: false)
|
|
|
|
|
testMatch("s0.v**", "s0.**", expect: true)
|
|
|
|
|
testMatch("s1.v**", "s0.**", expect: false)
|
|
|
|
|
testMatch("s0.**", "s0.v**", expect: false)
|
|
|
|
|
testMatch("s0.s1", "s0.i*.s1", expect: true)
|
|
|
|
|
testMatch("s0.b.s1", "s0.b.i*.s1", expect: true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testMatch(_ lhsStr: String, _ rhsStr: String, expect: Bool) {
|
|
|
|
|
var lhsParser = StringParser(lhsStr)
|
|
|
|
|
let lhs = try! lhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
var rhsParser = StringParser(rhsStr)
|
|
|
|
|
let rhs = try! rhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
let result = lhs.matches(pattern: rhs)
|
|
|
|
|
assert(result == expect)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func overlapping() {
|
|
|
|
|
testOverlap("s0.s1.s2", "s0.s1.s2", expect: true)
|
|
|
|
|
testOverlap("s0.s1.s2", "s0.s2.s2", expect: false)
|
|
|
|
|
testOverlap("s0.s1.s2", "s0.e1.s2", expect: false)
|
|
|
|
|
testOverlap("s0.s1.s2", "s0.s1", expect: true)
|
|
|
|
|
testOverlap("s0.s1.s2", "s1.s2", expect: false)
|
|
|
|
|
|
|
|
|
|
testOverlap("s0.c*.s2", "s0.ct.s2", expect: true)
|
|
|
|
|
testOverlap("s0.c*.s2", "s0.c1.s2", expect: true)
|
|
|
|
|
testOverlap("s0.c*.s2", "s0.c1.c2.s2", expect: false)
|
|
|
|
|
testOverlap("s0.c*.s2", "s0.s2", expect: false)
|
|
|
|
|
|
|
|
|
|
testOverlap("s0.v**.s2", "s0.s3.x", expect: true)
|
|
|
|
|
testOverlap("s0.v**.s2.c2", "s0.s3.c1", expect: false)
|
|
|
|
|
testOverlap("s0.v**.s2", "s1.s3", expect: false)
|
|
|
|
|
testOverlap("s0.v**.s2", "s0.v**.s3", expect: true)
|
|
|
|
|
|
|
|
|
|
testOverlap("s0.**", "s0.s3.c1", expect: true)
|
|
|
|
|
testOverlap("**", "s0.s3.c1", expect: true)
|
|
|
|
|
|
|
|
|
|
testOverlap("i1", "i*", expect: true)
|
|
|
|
|
testOverlap("i1", "v**", expect: true)
|
|
|
|
|
testOverlap("s0.i*.s1", "s0.s1", expect: true)
|
|
|
|
|
testOverlap("s0.b.s1", "s0.b.i*.s1", expect: true)
|
|
|
|
|
testOverlap("s0.b.i0.s1", "s0.b.i1.s1", expect: false)
|
|
|
|
|
testOverlap("s0.b.i2.s1", "s0.b.i1.s1", expect: false)
|
|
|
|
|
testOverlap("s0.b.s1", "s0.b.i0.s1", expect: true)
|
|
|
|
|
testOverlap("s0.b", "s0.b.i1", expect: false)
|
|
|
|
|
testOverlap("s0.b.i1", "s0.b", expect: false)
|
|
|
|
|
testOverlap("s0.b.i1", "s0", expect: true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testOverlap(_ lhsStr: String, _ rhsStr: String, expect: Bool) {
|
|
|
|
|
var lhsParser = StringParser(lhsStr)
|
|
|
|
|
let lhs = try! lhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
var rhsParser = StringParser(rhsStr)
|
|
|
|
|
let rhs = try! rhsParser.parseProjectionPathFromSIL()
|
|
|
|
|
let result = lhs.mayOverlap(with: rhs)
|
|
|
|
|
assert(result == expect)
|
|
|
|
|
let reversedResult = rhs.mayOverlap(with: lhs)
|
|
|
|
|
assert(reversedResult == expect)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func predicates() {
|
|
|
|
|
testPredicate("v**", \.hasClassProjection, expect: false)
|
|
|
|
|
testPredicate("v**.c0.s1.v**", \.hasClassProjection, expect: true)
|
|
|
|
|
testPredicate("c0.**", \.hasClassProjection, expect: true)
|
|
|
|
|
testPredicate("c0.c1", \.hasClassProjection, expect: true)
|
|
|
|
|
testPredicate("ct", \.hasClassProjection, expect: true)
|
|
|
|
|
testPredicate("s0", \.hasClassProjection, expect: false)
|
|
|
|
|
|
|
|
|
|
testPredicate("v**", \.mayHaveClassProjection, expect: false)
|
|
|
|
|
testPredicate("c0", \.mayHaveClassProjection, expect: true)
|
|
|
|
|
testPredicate("1", \.mayHaveClassProjection, expect: false)
|
|
|
|
|
testPredicate("**", \.mayHaveClassProjection, expect: true)
|
|
|
|
|
|
|
|
|
|
testPredicate("v**", \.mayHaveTwoClassProjections, expect: false)
|
|
|
|
|
testPredicate("c0", \.mayHaveTwoClassProjections, expect: false)
|
|
|
|
|
testPredicate("**", \.mayHaveTwoClassProjections, expect: true)
|
|
|
|
|
testPredicate("v**.c*.s2.1.c0", \.mayHaveTwoClassProjections, expect: true)
|
|
|
|
|
testPredicate("c*.s2.1.c0.v**", \.mayHaveTwoClassProjections, expect: true)
|
|
|
|
|
testPredicate("v**.c*.**", \.mayHaveTwoClassProjections, expect: true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testPredicate(_ pathStr: String, _ property: (SmallProjectionPath) -> Bool, expect: Bool) {
|
|
|
|
|
var parser = StringParser(pathStr)
|
|
|
|
|
let path = try! parser.parseProjectionPathFromSIL()
|
|
|
|
|
let result = property(path)
|
|
|
|
|
assert(result == expect)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func path2path() {
|
|
|
|
|
testPath2Path("s0.b.e2.3.c4.s1", { $0.popAllValueFields() }, expect: "c4.s1")
|
|
|
|
|
testPath2Path("v**.c4.s1", { $0.popAllValueFields() }, expect: "c4.s1")
|
|
|
|
|
testPath2Path("**", { $0.popAllValueFields() }, expect: "**")
|
|
|
|
|
|
|
|
|
|
testPath2Path("s0.e2.3.c4.s1.e2.v**.**", { $0.popLastClassAndValuesFromTail() }, expect: "s0.e2.3.c4.s1.e2.v**.**")
|
|
|
|
|
testPath2Path("s0.c2.3.c4.s1", { $0.popLastClassAndValuesFromTail() }, expect: "s0.c2.3")
|
|
|
|
|
testPath2Path("v**.c*.s1", { $0.popLastClassAndValuesFromTail() }, expect: "v**")
|
|
|
|
|
testPath2Path("s1.ct.v**", { $0.popLastClassAndValuesFromTail() }, expect: "s1")
|
|
|
|
|
testPath2Path("c0.c1.c2", { $0.popLastClassAndValuesFromTail() }, expect: "c0.c1")
|
|
|
|
|
testPath2Path("**", { $0.popLastClassAndValuesFromTail() }, expect: "**")
|
|
|
|
|
|
|
|
|
|
testPath2Path("v**.c3", { $0.popIfMatches(.anyValueFields) }, expect: "v**.c3")
|
|
|
|
|
testPath2Path("**", { $0.popIfMatches(.anyValueFields) }, expect: "**")
|
|
|
|
|
testPath2Path("s0.c3", { $0.popIfMatches(.anyValueFields) }, expect: nil)
|
|
|
|
|
|
|
|
|
|
testPath2Path("c0.s3", { $0.popIfMatches(.anyClassField) }, expect: nil)
|
|
|
|
|
testPath2Path("**", { $0.popIfMatches(.anyClassField) }, expect: "**")
|
|
|
|
|
testPath2Path("c*.e3", { $0.popIfMatches(.anyClassField) }, expect: "e3")
|
|
|
|
|
|
|
|
|
|
testPath2Path("i*.e3.s0", { $0.popIfMatches(.enumCase, index: 3) }, expect: "s0")
|
|
|
|
|
testPath2Path("i1.e3.s0", { $0.popIfMatches(.enumCase, index: 3) }, expect: nil)
|
|
|
|
|
testPath2Path("i*.e3.s0", { $0.popIfMatches(.indexedElement, index: 0) }, expect: "i*.e3.s0")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testPath2Path(_ pathStr: String, _ transform: (SmallProjectionPath) -> SmallProjectionPath?, expect: String?) {
|
|
|
|
|
var parser = StringParser(pathStr)
|
|
|
|
|
let path = try! parser.parseProjectionPathFromSIL()
|
|
|
|
|
let result = transform(path)
|
|
|
|
|
if let expect = expect {
|
|
|
|
|
var expectParser = StringParser(expect)
|
|
|
|
|
let expectPath = try! expectParser.parseProjectionPathFromSIL()
|
|
|
|
|
assert(result == expectPath)
|
|
|
|
|
} else {
|
|
|
|
|
assert(result == nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func indexedElements() {
|
|
|
|
|
let p1 = SmallProjectionPath(.indexedElement, index: 1)
|
|
|
|
|
let (k1, i1, s1) = p1.pop()
|
|
|
|
|
assert(k1 == .indexedElement && i1 == 1 && s1.isEmpty)
|
|
|
|
|
|
|
|
|
|
let p2 = SmallProjectionPath(.indexedElement, index: -1)
|
|
|
|
|
let (k2, _, s2) = p2.pop()
|
|
|
|
|
assert(k2 == .anything && s2.isEmpty)
|
|
|
|
|
|
|
|
|
|
let p3 = SmallProjectionPath(.indexedElement, index: 0xfffffffffffff)
|
|
|
|
|
let (k3, i3, s3) = p3.pop()
|
|
|
|
|
assert(k3 == .indexedElement && i3 == 0xfffffffffffff && s3.isEmpty)
|
|
|
|
|
|
|
|
|
|
let p4 = p3.push(.indexedElement, index: Int.max)
|
|
|
|
|
let (k4, _, s4) = p4.pop()
|
|
|
|
|
assert(k4 == .anyIndexedElement && s4.isEmpty)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|