stdlib: Fix hasPrefix,hasSuffix tests

Comparing unicodeScalars like this is not valid.

Swift SVN r31477
This commit is contained in:
Arnold Schwaighofer
2015-08-26 03:57:25 +00:00
parent 2588f44d83
commit 3cc2dae6e6

View File

@@ -1842,16 +1842,22 @@ NSStringAPIs.test("stringByApplyingTransform(_:reverse:)") {
struct ComparisonTest { struct ComparisonTest {
let expectedUnicodeCollation: ExpectedComparisonResult let expectedUnicodeCollation: ExpectedComparisonResult
let expectedHasPrefix: Bool
let expectedHasSuffix: Bool
let lhs: String let lhs: String
let rhs: String let rhs: String
let loc: SourceLoc let loc: SourceLoc
init( init(
hasPrefix: Bool,
hasSuffix: Bool,
_ expectedUnicodeCollation: ExpectedComparisonResult, _ expectedUnicodeCollation: ExpectedComparisonResult,
_ lhs: String, _ rhs: String, _ lhs: String, _ rhs: String,
file: String = __FILE__, line: UInt = __LINE__ file: String = __FILE__, line: UInt = __LINE__
) { ) {
self.expectedUnicodeCollation = expectedUnicodeCollation self.expectedUnicodeCollation = expectedUnicodeCollation
self.expectedHasPrefix = hasPrefix
self.expectedHasSuffix = hasSuffix
self.lhs = lhs self.lhs = lhs
self.rhs = rhs self.rhs = rhs
self.loc = SourceLoc(file, line, comment: "test data") self.loc = SourceLoc(file, line, comment: "test data")
@@ -1859,23 +1865,23 @@ struct ComparisonTest {
} }
let comparisonTests = [ let comparisonTests = [
ComparisonTest(.EQ, "", ""), ComparisonTest(hasPrefix: false, hasSuffix: false, .EQ, "", ""),
ComparisonTest(.LT, "", "a"), ComparisonTest(hasPrefix: false, hasSuffix: false, .LT, "", "a"),
// ASCII cases // ASCII cases
ComparisonTest(.LT, "t", "tt"), ComparisonTest(hasPrefix: false, hasSuffix: false, .LT, "t", "tt"),
ComparisonTest(hasPrefix: true, hasSuffix: true, .GT, "tt", "t"),
// According to DUCET: a < A < b < B. // According to DUCET: a < A < b < B.
// This is NOT ascii order. // This is NOT ascii order.
ComparisonTest(.GT, "T", "t"), ComparisonTest(hasPrefix: false, hasSuffix: false, .GT, "T", "t"),
// According to DUCET \0 has no collation value and so is ignored in the // According to DUCET \0 has no collation value and so is ignored in the
// ordering relation. // ordering relation.
ComparisonTest(.EQ, "\u{0}", ""), ComparisonTest(hasPrefix: false, hasSuffix: false, .EQ, "\u{0}", ""),
ComparisonTest(.EQ, "\u{1}", "\u{0}"), ComparisonTest(hasPrefix: false, hasSuffix: false, .EQ, "\u{1}", "\u{0}"),
ComparisonTest(.LT, "\r\n", "t"), ComparisonTest(hasPrefix: false, hasSuffix: false, .LT, "\r\n", "t"),
// Currently fails: ComparisonTest(hasPrefix: false, hasSuffix: true, .GT, "\r\n", "\n"),
//ComparisonTest(.GT, "\r\n", "\n"), ComparisonTest(hasPrefix: false, hasSuffix: false, .EQ, "\u{0}", "\u{0}\u{0}"),
ComparisonTest(hasPrefix: false, hasSuffix: true, .EQ, "\u{0}\u{0}", "\u{0}"),
ComparisonTest(.EQ, "\u{0}", "\u{0}\u{0}"),
// Whitespace // Whitespace
// U+000A LINE FEED (LF) // U+000A LINE FEED (LF)
@@ -1884,57 +1890,58 @@ let comparisonTests = [
// U+0085 NEXT LINE (NEL) // U+0085 NEXT LINE (NEL)
// U+2028 LINE SEPARATOR // U+2028 LINE SEPARATOR
// U+2029 PARAGRAPH SEPARATOR // U+2029 PARAGRAPH SEPARATOR
ComparisonTest(.GT, "\u{0085}", "\n"), ComparisonTest(hasPrefix: false, hasSuffix: false, .GT, "\u{0085}", "\n"),
ComparisonTest(.GT, "\u{000b}", "\n"), ComparisonTest(hasPrefix: false, hasSuffix: false, .GT, "\u{000b}", "\n"),
ComparisonTest(.GT, "\u{000c}", "\n"), ComparisonTest(hasPrefix: false, hasSuffix: false, .GT, "\u{000c}", "\n"),
ComparisonTest(.GT, "\u{2028}", "\n"), ComparisonTest(hasPrefix: false, hasSuffix: false, .GT, "\u{2028}", "\n"),
ComparisonTest(.GT, "\u{2029}", "\n"), ComparisonTest(hasPrefix: false, hasSuffix: false, .GT, "\u{2029}", "\n"),
ComparisonTest(.GT, "\r\n\r\n", "\r\n"), ComparisonTest(hasPrefix: true, hasSuffix: true, .GT, "\r\n\r\n", "\r\n"),
// U+0301 COMBINING ACUTE ACCENT // U+0301 COMBINING ACUTE ACCENT
// U+00E1 LATIN SMALL LETTER A WITH ACUTE // U+00E1 LATIN SMALL LETTER A WITH ACUTE
ComparisonTest(.EQ, "a\u{301}", "\u{e1}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "a\u{301}", "\u{e1}"),
ComparisonTest(.LT, "a", "a\u{301}"), ComparisonTest(hasPrefix: false, hasSuffix: false, .LT, "a", "a\u{301}"),
ComparisonTest(.LT, "a", "\u{e1}"), ComparisonTest(hasPrefix: false, hasSuffix: false, .LT, "a", "\u{e1}"),
// U+304B HIRAGANA LETTER KA // U+304B HIRAGANA LETTER KA
// U+304C HIRAGANA LETTER GA // U+304C HIRAGANA LETTER GA
// U+3099 COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK // U+3099 COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK
ComparisonTest(.EQ, "\u{304b}", "\u{304b}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{304b}", "\u{304b}"),
ComparisonTest(.EQ, "\u{304c}", "\u{304c}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{304c}", "\u{304c}"),
ComparisonTest(.LT, "\u{304b}", "\u{304c}"), ComparisonTest(hasPrefix: false, hasSuffix: false, .LT, "\u{304b}", "\u{304c}"),
ComparisonTest(.LT, "\u{304b}", "\u{304c}\u{3099}"), ComparisonTest(hasPrefix: false, hasSuffix: false, .LT, "\u{304b}", "\u{304c}\u{3099}"),
ComparisonTest(.EQ, "\u{304c}", "\u{304b}\u{3099}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{304c}", "\u{304b}\u{3099}"),
ComparisonTest(.LT, "\u{304c}", "\u{304c}\u{3099}"), ComparisonTest(hasPrefix: false, hasSuffix: false, .LT, "\u{304c}", "\u{304c}\u{3099}"),
// U+212B ANGSTROM SIGN // U+212B ANGSTROM SIGN
// U+030A COMBINING RING ABOVE // U+030A COMBINING RING ABOVE
// U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE // U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE
ComparisonTest(.EQ, "\u{212b}", "A\u{30a}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{212b}", "A\u{30a}"),
ComparisonTest(.EQ, "\u{212b}", "\u{c5}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{212b}", "\u{c5}"),
ComparisonTest(.EQ, "A\u{30a}", "\u{c5}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "A\u{30a}", "\u{c5}"),
ComparisonTest(.GT, "A\u{30a}", "a"), ComparisonTest(hasPrefix: false, hasSuffix: false, .GT, "A\u{30a}", "a"),
ComparisonTest(.LT, "A", "A\u{30a}"), ComparisonTest(hasPrefix: false, hasSuffix: false, .LT, "A", "A\u{30a}"),
// U+2126 OHM SIGN // U+2126 OHM SIGN
// U+03A9 GREEK CAPITAL LETTER OMEGA // U+03A9 GREEK CAPITAL LETTER OMEGA
ComparisonTest(.EQ, "\u{2126}", "\u{03a9}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{2126}", "\u{03a9}"),
// U+0323 COMBINING DOT BELOW // U+0323 COMBINING DOT BELOW
// U+0307 COMBINING DOT ABOVE // U+0307 COMBINING DOT ABOVE
// U+1E63 LATIN SMALL LETTER S WITH DOT BELOW // U+1E63 LATIN SMALL LETTER S WITH DOT BELOW
// U+1E69 LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE // U+1E69 LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE
ComparisonTest(.EQ, "\u{1e69}", "s\u{323}\u{307}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{1e69}", "s\u{323}\u{307}"),
ComparisonTest(.EQ, "\u{1e69}", "s\u{307}\u{323}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{1e69}", "s\u{307}\u{323}"),
ComparisonTest(.EQ, "\u{1e69}", "\u{1e63}\u{307}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{1e69}", "\u{1e63}\u{307}"),
ComparisonTest(.EQ, "\u{1e63}", "s\u{323}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{1e63}", "s\u{323}"),
ComparisonTest(.EQ, "\u{1e63}\u{307}", "s\u{323}\u{307}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{1e63}\u{307}", "s\u{323}\u{307}"),
ComparisonTest(.EQ, "\u{1e63}\u{307}", "s\u{307}\u{323}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{1e63}\u{307}", "s\u{307}\u{323}"),
ComparisonTest(.LT, "s\u{323}", "\u{1e69}"), ComparisonTest(hasPrefix: false, hasSuffix: false, .LT, "s\u{323}", "\u{1e69}"),
// U+FB01 LATIN SMALL LIGATURE FI // U+FB01 LATIN SMALL LIGATURE FI
ComparisonTest(.EQ, "\u{fb01}", "\u{fb01}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{fb01}", "\u{fb01}"),
ComparisonTest(.LT, "fi", "\u{fb01}"), ComparisonTest(hasPrefix: false, hasSuffix: false, .LT, "fi", "\u{fb01}"),
// We don't perform Unicode collation in semi-stable mode. // We don't perform Unicode collation in semi-stable mode.
// //
@@ -1949,9 +1956,9 @@ let comparisonTests = [
// //
// U+0301 and U+0954 don't decompose in the canonical decomposition mapping. // U+0301 and U+0954 don't decompose in the canonical decomposition mapping.
// U+0341 has a canonical decomposition mapping of U+0301. // U+0341 has a canonical decomposition mapping of U+0301.
ComparisonTest(.EQ, "\u{0301}", "\u{0341}"), ComparisonTest(hasPrefix: true, hasSuffix: true, .EQ, "\u{0301}", "\u{0341}"),
ComparisonTest(.EQ, "\u{0301}", "\u{0954}"), ComparisonTest(hasPrefix: false, hasSuffix: false, .EQ, "\u{0301}", "\u{0954}"),
ComparisonTest(.EQ, "\u{0341}", "\u{0954}"), ComparisonTest(hasPrefix: false, hasSuffix: false, .EQ, "\u{0341}", "\u{0954}"),
] ]
func forceUTF16String(var str: String) -> String { func forceUTF16String(var str: String) -> String {
@@ -2068,7 +2075,8 @@ NSStringAPIs.test("Character.{Equatable,Hashable,Comparable}") {
} }
func checkHasPrefixHasSuffix( func checkHasPrefixHasSuffix(
lhs: String, _ rhs: String, _ stackTrace: SourceLocStack expectedHasPrefix: Bool, _ expectedHasSuffix: Bool, _ lhs: String,
_ rhs: String, _ stackTrace: SourceLocStack
) { ) {
if lhs == "" { if lhs == "" {
return return
@@ -2079,49 +2087,18 @@ func checkHasPrefixHasSuffix(
return return
} }
// To determine the expected results, compare grapheme clusters, expectEqual(expectedHasPrefix, lhs.hasPrefix(rhs), stackTrace: stackTrace)
// scalar-to-scalar, of the NFD form of the strings.
let lhsNFDGraphemeClusters =
lhs.decomposedStringWithCanonicalMapping.characters.map {
Array(String($0).unicodeScalars)
}
let rhsNFDGraphemeClusters =
rhs.decomposedStringWithCanonicalMapping.characters.map {
Array(String($0).unicodeScalars)
}
let expectHasPrefix = lhsNFDGraphemeClusters.startsWith(
rhsNFDGraphemeClusters, isEquivalent: (==))
let expectHasSuffix =
lhsNFDGraphemeClusters.lazy.reverse().startsWith(
rhsNFDGraphemeClusters.lazy.reverse(), isEquivalent: (==))
expectEqual(expectHasPrefix, lhs.hasPrefix(rhs), stackTrace: stackTrace)
expectEqual( expectEqual(
expectHasPrefix, (lhs + "abc").hasPrefix(rhs), stackTrace: stackTrace) expectedHasPrefix, (lhs + "abc").hasPrefix(rhs), stackTrace: stackTrace)
expectEqual(expectHasSuffix, lhs.hasSuffix(rhs), stackTrace: stackTrace) expectEqual(expectedHasSuffix, lhs.hasSuffix(rhs), stackTrace: stackTrace)
expectEqual( expectEqual(
expectHasSuffix, ("abc" + lhs).hasSuffix(rhs), stackTrace: stackTrace) expectedHasSuffix, ("abc" + lhs).hasSuffix(rhs), stackTrace: stackTrace)
} }
NSStringAPIs.test("hasPrefix,hasSuffix") { NSStringAPIs.test("hasPrefix,hasSuffix") {
for test in comparisonTests { for test in comparisonTests {
checkHasPrefixHasSuffix(test.lhs, test.rhs, test.loc.withCurrentLoc()) checkHasPrefixHasSuffix(test.expectedHasPrefix, test.expectedHasSuffix,
checkHasPrefixHasSuffix(test.rhs, test.lhs, test.loc.withCurrentLoc()) test.lhs, test.rhs, test.loc.withCurrentLoc())
}
}
NSStringAPIs.test("Failures{hasPrefix,hasSuffix}-CF") {
//.xfail(.Custom({ true }, reason: "rdar://problem/19034601")).code {
let test = ComparisonTest(.LT, "\u{0}", "\u{0}\u{0}")
checkHasPrefixHasSuffix(test.lhs, test.rhs, test.loc.withCurrentLoc())
}
NSStringAPIs.test("Failures{hasPrefix,hasSuffix}")
.xfail(.Custom({ true }, reason: "blocked on rdar://problem/19036555")).code {
let tests =
[ComparisonTest(.LT, "\r\n", "t"), ComparisonTest(.GT, "\r\n", "\n")]
tests.forEach {
checkHasPrefixHasSuffix($0.lhs, $0.rhs, $0.loc.withCurrentLoc())
} }
} }