1describe("unittests:: services:: PatternMatcher", () => { 2 describe("BreakIntoCharacterSpans", () => { 3 it("EmptyIdentifier", () => { 4 verifyBreakIntoCharacterSpans(""); 5 }); 6 7 it("SimpleIdentifier", () => { 8 verifyBreakIntoCharacterSpans("foo", "foo"); 9 }); 10 11 it("PrefixUnderscoredIdentifier", () => { 12 verifyBreakIntoCharacterSpans("_foo", "_", "foo"); 13 }); 14 15 it("UnderscoredIdentifier", () => { 16 verifyBreakIntoCharacterSpans("f_oo", "f", "_", "oo"); 17 }); 18 19 it("PostfixUnderscoredIdentifier", () => { 20 verifyBreakIntoCharacterSpans("foo_", "foo", "_"); 21 }); 22 23 it("PrefixUnderscoredIdentifierWithCapital", () => { 24 verifyBreakIntoCharacterSpans("_Foo", "_", "Foo"); 25 }); 26 27 it("MUnderscorePrefixed", () => { 28 verifyBreakIntoCharacterSpans("m_foo", "m", "_", "foo"); 29 }); 30 31 it("CamelCaseIdentifier", () => { 32 verifyBreakIntoCharacterSpans("FogBar", "Fog", "Bar"); 33 }); 34 35 it("MixedCaseIdentifier", () => { 36 verifyBreakIntoCharacterSpans("fogBar", "fog", "Bar"); 37 }); 38 39 it("TwoCharacterCapitalIdentifier", () => { 40 verifyBreakIntoCharacterSpans("UIElement", "U", "I", "Element"); 41 }); 42 43 it("NumberSuffixedIdentifier", () => { 44 verifyBreakIntoCharacterSpans("Foo42", "Foo", "42"); 45 }); 46 47 it("NumberContainingIdentifier", () => { 48 verifyBreakIntoCharacterSpans("Fog42Bar", "Fog", "42", "Bar"); 49 }); 50 51 it("NumberPrefixedIdentifier", () => { 52 verifyBreakIntoCharacterSpans("42Bar", "42", "Bar"); 53 }); 54 }); 55 56 describe("BreakIntoWordSpans", () => { 57 it("VarbatimIdentifier", () => { 58 verifyBreakIntoWordSpans("@int:", "int"); 59 }); 60 61 it("AllCapsConstant", () => { 62 verifyBreakIntoWordSpans("C_STYLE_CONSTANT", "C", "_", "STYLE", "_", "CONSTANT"); 63 }); 64 65 it("SingleLetterPrefix1", () => { 66 verifyBreakIntoWordSpans("UInteger", "U", "Integer"); 67 }); 68 69 it("SingleLetterPrefix2", () => { 70 verifyBreakIntoWordSpans("IDisposable", "I", "Disposable"); 71 }); 72 73 it("TwoCharacterCapitalIdentifier", () => { 74 verifyBreakIntoWordSpans("UIElement", "UI", "Element"); 75 }); 76 77 it("XDocument", () => { 78 verifyBreakIntoWordSpans("XDocument", "X", "Document"); 79 }); 80 81 it("XMLDocument1", () => { 82 verifyBreakIntoWordSpans("XMLDocument", "XML", "Document"); 83 }); 84 85 it("XMLDocument2", () => { 86 verifyBreakIntoWordSpans("XmlDocument", "Xml", "Document"); 87 }); 88 89 it("TwoUppercaseCharacters", () => { 90 verifyBreakIntoWordSpans("SimpleUIElement", "Simple", "UI", "Element"); 91 }); 92 }); 93 94 describe("SingleWordPattern", () => { 95 it("PreferCaseSensitiveExact", () => { 96 assertSegmentMatch("Foo", "Foo", { kind: ts.PatternMatchKind.exact, isCaseSensitive: true }); 97 }); 98 99 it("PreferCaseSensitiveExactInsensitive", () => { 100 assertSegmentMatch("foo", "Foo", { kind: ts.PatternMatchKind.exact, isCaseSensitive: false }); 101 }); 102 103 it("PreferCaseSensitivePrefix", () => { 104 assertSegmentMatch("Foo", "Fo", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); 105 }); 106 107 it("PreferCaseSensitivePrefixCaseInsensitive", () => { 108 assertSegmentMatch("Foo", "fo", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: false }); 109 }); 110 111 it("PreferCaseSensitiveCamelCaseMatchSimple", () => { 112 assertSegmentMatch("FogBar", "FB", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); 113 }); 114 115 it("PreferCaseSensitiveCamelCaseMatchPartialPattern", () => { 116 assertSegmentMatch("FogBar", "FoB", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); 117 }); 118 119 it("PreferCaseSensitiveCamelCaseMatchToLongPattern1", () => { 120 assertSegmentMatch("FogBar", "FBB", undefined); 121 }); 122 123 it("PreferCaseSensitiveCamelCaseMatchToLongPattern2", () => { 124 assertSegmentMatch("FogBar", "FoooB", undefined); 125 }); 126 127 it("CamelCaseMatchPartiallyUnmatched", () => { 128 assertSegmentMatch("FogBarBaz", "FZ", undefined); 129 }); 130 131 it("CamelCaseMatchCompletelyUnmatched", () => { 132 assertSegmentMatch("FogBarBaz", "ZZ", undefined); 133 }); 134 135 it("TwoUppercaseCharacters", () => { 136 assertSegmentMatch("SimpleUIElement", "SiUI", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); 137 }); 138 139 it("PreferCaseSensitiveLowercasePattern", () => { 140 assertSegmentMatch("FogBar", "b", { kind: ts.PatternMatchKind.substring, isCaseSensitive: false }); 141 }); 142 143 it("PreferCaseSensitiveLowercasePattern2", () => { 144 assertSegmentMatch("FogBar", "fB", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: false }); 145 }); 146 147 it("PreferCaseSensitiveTryUnderscoredName", () => { 148 assertSegmentMatch("_fogBar", "_fB", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); 149 }); 150 151 it("PreferCaseSensitiveTryUnderscoredName2", () => { 152 assertSegmentMatch("_fogBar", "fB", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); 153 }); 154 155 it("PreferCaseSensitiveTryUnderscoredNameInsensitive", () => { 156 assertSegmentMatch("_FogBar", "_fB", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: false }); 157 }); 158 159 it("PreferCaseSensitiveMiddleUnderscore", () => { 160 assertSegmentMatch("Fog_Bar", "FB", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); 161 }); 162 163 it("PreferCaseSensitiveMiddleUnderscore2", () => { 164 assertSegmentMatch("Fog_Bar", "F_B", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); 165 }); 166 167 it("PreferCaseSensitiveMiddleUnderscore3", () => { 168 assertSegmentMatch("Fog_Bar", "F__B", undefined); 169 }); 170 171 it("PreferCaseSensitiveMiddleUnderscore4", () => { 172 assertSegmentMatch("Fog_Bar", "f_B", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: false }); 173 }); 174 175 it("PreferCaseSensitiveMiddleUnderscore5", () => { 176 assertSegmentMatch("Fog_Bar", "F_b", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: false }); 177 }); 178 179 it("AllLowerPattern1", () => { 180 assertSegmentMatch("FogBarChangedEventArgs", "changedeventargs", { kind: ts.PatternMatchKind.substring, isCaseSensitive: false }); 181 }); 182 183 it("AllLowerPattern2", () => { 184 assertSegmentMatch("FogBarChangedEventArgs", "changedeventarrrgh", undefined); 185 }); 186 187 it("AllLowerPattern3", () => { 188 assertSegmentMatch("ABCDEFGH", "bcd", { kind: ts.PatternMatchKind.substring, isCaseSensitive: false }); 189 }); 190 191 it("AllLowerPattern4", () => { 192 assertSegmentMatch("AbcdefghijEfgHij", "efghij", undefined); 193 }); 194 }); 195 196 describe("MultiWordPattern", () => { 197 it("ExactWithLowercase", () => { 198 assertSegmentMatch("AddMetadataReference", "addmetadatareference", { kind: ts.PatternMatchKind.exact, isCaseSensitive: false }); 199 }); 200 201 it("SingleLowercasedSearchWord1", () => { 202 assertSegmentMatch("AddMetadataReference", "add", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: false }); 203 }); 204 205 it("SingleLowercasedSearchWord2", () => { 206 assertSegmentMatch("AddMetadataReference", "metadata", { kind: ts.PatternMatchKind.substring, isCaseSensitive: false }); 207 }); 208 209 it("SingleUppercaseSearchWord1", () => { 210 assertSegmentMatch("AddMetadataReference", "Add", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); 211 }); 212 213 it("SingleUppercaseSearchWord2", () => { 214 assertSegmentMatch("AddMetadataReference", "Metadata", { kind: ts.PatternMatchKind.substring, isCaseSensitive: true }); 215 }); 216 217 it("SingleUppercaseSearchLetter1", () => { 218 assertSegmentMatch("AddMetadataReference", "A", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); 219 }); 220 221 it("SingleUppercaseSearchLetter2", () => { 222 assertSegmentMatch("AddMetadataReference", "M", { kind: ts.PatternMatchKind.substring, isCaseSensitive: true }); 223 }); 224 225 it("TwoLowercaseWords0", () => { 226 assertSegmentMatch("AddMetadataReference", "add metadata", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: false }); 227 }); 228 229 it("TwoLowercaseWords1", () => { 230 assertSegmentMatch("AddMetadataReference", "A M", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); 231 }); 232 233 it("TwoLowercaseWords2", () => { 234 assertSegmentMatch("AddMetadataReference", "AM", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); 235 }); 236 237 it("TwoLowercaseWords3", () => { 238 assertSegmentMatch("AddMetadataReference", "ref Metadata", { kind: ts.PatternMatchKind.substring, isCaseSensitive: true }); 239 }); 240 241 it("TwoLowercaseWords4", () => { 242 assertSegmentMatch("AddMetadataReference", "ref M", { kind: ts.PatternMatchKind.substring, isCaseSensitive: true }); 243 }); 244 245 it("MixedCamelCase", () => { 246 assertSegmentMatch("AddMetadataReference", "AMRe", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); 247 }); 248 249 it("BlankPattern", () => { 250 assertInvalidPattern(""); 251 }); 252 253 it("WhitespaceOnlyPattern", () => { 254 assertInvalidPattern(" "); 255 }); 256 257 it("EachWordSeparately1", () => { 258 assertSegmentMatch("AddMetadataReference", "add Meta", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: false }); 259 }); 260 261 it("EachWordSeparately2", () => { 262 assertSegmentMatch("AddMetadataReference", "Add meta", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); 263 }); 264 265 it("EachWordSeparately3", () => { 266 assertSegmentMatch("AddMetadataReference", "Add Meta", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); 267 }); 268 269 it("MixedCasing", () => { 270 assertSegmentMatch("AddMetadataReference", "mEta", undefined); 271 }); 272 273 it("MixedCasing2", () => { 274 assertSegmentMatch("AddMetadataReference", "Data", undefined); 275 }); 276 277 it("AsteriskSplit", () => { 278 assertSegmentMatch("GetKeyWord", "K*W", { kind: ts.PatternMatchKind.substring, isCaseSensitive: true }); 279 }); 280 281 it("LowercaseSubstring1", () => { 282 assertSegmentMatch("Operator", "a", undefined); 283 }); 284 285 it("LowercaseSubstring2", () => { 286 assertSegmentMatch("FooAttribute", "a", { kind: ts.PatternMatchKind.substring, isCaseSensitive: false }); 287 }); 288 }); 289 290 describe("DottedPattern", () => { 291 it("DottedPattern1", () => { 292 assertFullMatch("Foo.Bar.Baz", "Quux", "B.Q", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); 293 }); 294 295 it("DottedPattern2", () => { 296 assertFullMatch("Foo.Bar.Baz", "Quux", "C.Q", undefined); 297 }); 298 299 it("DottedPattern3", () => { 300 assertFullMatch("Foo.Bar.Baz", "Quux", "B.B.Q", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); 301 }); 302 303 it("DottedPattern4", () => { 304 assertFullMatch("Foo.Bar.Baz", "Quux", "Baz.Quux", { kind: ts.PatternMatchKind.exact, isCaseSensitive: true }); 305 }); 306 307 it("DottedPattern5", () => { 308 assertFullMatch("Foo.Bar.Baz", "Quux", "F.B.B.Quux", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); 309 }); 310 311 it("DottedPattern6", () => { 312 assertFullMatch("Foo.Bar.Baz", "Quux", "F.F.B.B.Quux", undefined); 313 }); 314 315 it("DottedPattern7", () => { 316 assertSegmentMatch("UIElement", "UIElement", { kind: ts.PatternMatchKind.exact, isCaseSensitive: true }); 317 assertSegmentMatch("GetKeyword", "UIElement", undefined); 318 }); 319 }); 320 321 function assertSegmentMatch(candidate: string, pattern: string, expected: ts.PatternMatch | undefined): void { 322 assert.deepEqual(ts.createPatternMatcher(pattern)!.getMatchForLastSegmentOfPattern(candidate), expected); 323 } 324 325 function assertInvalidPattern(pattern: string) { 326 assert.equal(ts.createPatternMatcher(pattern), undefined); 327 } 328 329 function assertFullMatch(dottedContainer: string, candidate: string, pattern: string, expected: ts.PatternMatch | undefined): void { 330 assert.deepEqual(ts.createPatternMatcher(pattern)!.getFullMatch(dottedContainer.split("."), candidate), expected); 331 } 332 333 function spanListToSubstrings(identifier: string, spans: ts.TextSpan[]) { 334 return spans.map(s => identifier.substr(s.start, s.length)); 335 } 336 337 function breakIntoCharacterSpans(identifier: string) { 338 return spanListToSubstrings(identifier, ts.breakIntoCharacterSpans(identifier)); 339 } 340 341 function breakIntoWordSpans(identifier: string) { 342 return spanListToSubstrings(identifier, ts.breakIntoWordSpans(identifier)); 343 } 344 345 function verifyBreakIntoCharacterSpans(original: string, ...parts: string[]): void { 346 assert.deepEqual(parts, breakIntoCharacterSpans(original)); 347 } 348 349 function verifyBreakIntoWordSpans(original: string, ...parts: string[]): void { 350 assert.deepEqual(parts, breakIntoWordSpans(original)); 351 } 352}); 353