/// /// describe("PatternMatcher", function () { describe("BreakIntoCharacterSpans", function () { it("EmptyIdentifier", () => { verifyBreakIntoCharacterSpans(""); }); it("SimpleIdentifier", () => { verifyBreakIntoCharacterSpans("foo", "foo"); }); it("PrefixUnderscoredIdentifier", () => { verifyBreakIntoCharacterSpans("_foo", "_", "foo"); }); it("UnderscoredIdentifier", () => { verifyBreakIntoCharacterSpans("f_oo", "f", "_", "oo"); }); it("PostfixUnderscoredIdentifier", () => { verifyBreakIntoCharacterSpans("foo_", "foo", "_"); }); it("PrefixUnderscoredIdentifierWithCapital", () => { verifyBreakIntoCharacterSpans("_Foo", "_", "Foo"); }); it("MUnderscorePrefixed", () => { verifyBreakIntoCharacterSpans("m_foo", "m", "_", "foo"); }); it("CamelCaseIdentifier", () => { verifyBreakIntoCharacterSpans("FogBar", "Fog", "Bar"); }); it("MixedCaseIdentifier", () => { verifyBreakIntoCharacterSpans("fogBar", "fog", "Bar"); }); it("TwoCharacterCapitalIdentifier", () => { verifyBreakIntoCharacterSpans("UIElement", "U", "I", "Element"); }); it("NumberSuffixedIdentifier", () => { verifyBreakIntoCharacterSpans("Foo42", "Foo", "42"); }); it("NumberContainingIdentifier", () => { verifyBreakIntoCharacterSpans("Fog42Bar", "Fog", "42", "Bar"); }); it("NumberPrefixedIdentifier", () => { verifyBreakIntoCharacterSpans("42Bar", "42", "Bar"); }); }); describe("BreakIntoWordSpans", function () { it("VarbatimIdentifier", () => { verifyBreakIntoWordSpans("@int:", "int"); }); it("AllCapsConstant", () => { verifyBreakIntoWordSpans("C_STYLE_CONSTANT", "C", "_", "STYLE", "_", "CONSTANT"); }); it("SingleLetterPrefix1", () => { verifyBreakIntoWordSpans("UInteger", "U", "Integer"); }); it("SingleLetterPrefix2", () => { verifyBreakIntoWordSpans("IDisposable", "I", "Disposable"); }); it("TwoCharacterCapitalIdentifier", () => { verifyBreakIntoWordSpans("UIElement", "UI", "Element"); }); it("XDocument", () => { verifyBreakIntoWordSpans("XDocument", "X", "Document"); }); it("XMLDocument1", () => { verifyBreakIntoWordSpans("XMLDocument", "XML", "Document"); }); it("XMLDocument2", () => { verifyBreakIntoWordSpans("XmlDocument", "Xml", "Document"); }); it("TwoUppercaseCharacters", () => { verifyBreakIntoWordSpans("SimpleUIElement", "Simple", "UI", "Element"); }); }); describe("SingleWordPattern", () => { it("PreferCaseSensitiveExact", () => { const match = getFirstMatch("Foo", "Foo"); assert.equal(ts.PatternMatchKind.exact, match.kind); assert.equal(true, match.isCaseSensitive); }); it("PreferCaseSensitiveExactInsensitive", () => { const match = getFirstMatch("foo", "Foo"); assert.equal(ts.PatternMatchKind.exact, match.kind); assert.equal(false, match.isCaseSensitive); }); it("PreferCaseSensitivePrefix", () => { const match = getFirstMatch("Foo", "Fo"); assert.equal(ts.PatternMatchKind.prefix, match.kind); assert.equal(true, match.isCaseSensitive); }); it("PreferCaseSensitivePrefixCaseInsensitive", () => { const match = getFirstMatch("Foo", "fo"); assert.equal(ts.PatternMatchKind.prefix, match.kind); assert.equal(false, match.isCaseSensitive); }); it("PreferCaseSensitiveCamelCaseMatchSimple", () => { const match = getFirstMatch("FogBar", "FB"); assert.equal(ts.PatternMatchKind.camelCase, match.kind); assert.equal(true, match.isCaseSensitive); assertInRange(match.camelCaseWeight, 1, 1 << 30); }); it("PreferCaseSensitiveCamelCaseMatchPartialPattern", () => { const match = getFirstMatch("FogBar", "FoB"); assert.equal(ts.PatternMatchKind.camelCase, match.kind); assert.equal(true, match.isCaseSensitive); }); it("PreferCaseSensitiveCamelCaseMatchToLongPattern1", () => { const match = getFirstMatch("FogBar", "FBB"); assert.isTrue(match === undefined); }); it("PreferCaseSensitiveCamelCaseMatchToLongPattern2", () => { const match = getFirstMatch("FogBar", "FoooB"); assert.isTrue(match === undefined); }); it("CamelCaseMatchPartiallyUnmatched", () => { const match = getFirstMatch("FogBarBaz", "FZ"); assert.isTrue(match === undefined); }); it("CamelCaseMatchCompletelyUnmatched", () => { const match = getFirstMatch("FogBarBaz", "ZZ"); assert.isTrue(match === undefined); }); it("TwoUppercaseCharacters", () => { const match = getFirstMatch("SimpleUIElement", "SiUI"); assert.equal(ts.PatternMatchKind.camelCase, match.kind); assert.equal(true, match.isCaseSensitive); }); it("PreferCaseSensitiveLowercasePattern", () => { const match = getFirstMatch("FogBar", "b"); assert.equal(ts.PatternMatchKind.substring, match.kind); assert.equal(false, match.isCaseSensitive); }); it("PreferCaseSensitiveLowercasePattern2", () => { const match = getFirstMatch("FogBar", "fB"); assert.equal(ts.PatternMatchKind.camelCase, match.kind); assert.equal(false, match.isCaseSensitive); }); it("PreferCaseSensitiveTryUnderscoredName", () => { const match = getFirstMatch("_fogBar", "_fB"); assert.equal(ts.PatternMatchKind.camelCase, match.kind); assert.equal(true, match.isCaseSensitive); }); it("PreferCaseSensitiveTryUnderscoredName2", () => { const match = getFirstMatch("_fogBar", "fB"); assert.equal(ts.PatternMatchKind.camelCase, match.kind); assert.equal(true, match.isCaseSensitive); }); it("PreferCaseSensitiveTryUnderscoredNameInsensitive", () => { const match = getFirstMatch("_FogBar", "_fB"); assert.equal(ts.PatternMatchKind.camelCase, match.kind); assert.equal(false, match.isCaseSensitive); }); it("PreferCaseSensitiveMiddleUnderscore", () => { const match = getFirstMatch("Fog_Bar", "FB"); assert.equal(ts.PatternMatchKind.camelCase, match.kind); assert.equal(true, match.isCaseSensitive); }); it("PreferCaseSensitiveMiddleUnderscore2", () => { const match = getFirstMatch("Fog_Bar", "F_B"); assert.equal(ts.PatternMatchKind.camelCase, match.kind); assert.equal(true, match.isCaseSensitive); }); it("PreferCaseSensitiveMiddleUnderscore3", () => { const match = getFirstMatch("Fog_Bar", "F__B"); assert.isTrue(undefined === match); }); it("PreferCaseSensitiveMiddleUnderscore4", () => { const match = getFirstMatch("Fog_Bar", "f_B"); assert.equal(ts.PatternMatchKind.camelCase, match.kind); assert.equal(false, match.isCaseSensitive); }); it("PreferCaseSensitiveMiddleUnderscore5", () => { const match = getFirstMatch("Fog_Bar", "F_b"); assert.equal(ts.PatternMatchKind.camelCase, match.kind); assert.equal(false, match.isCaseSensitive); }); it("PreferCaseSensitiveRelativeWeights1", () => { const match1 = getFirstMatch("FogBarBaz", "FB"); const match2 = getFirstMatch("FooFlobBaz", "FB"); // We should prefer something that starts at the beginning if possible assertInRange(match1.camelCaseWeight, match2.camelCaseWeight + 1, 1 << 30); }); it("PreferCaseSensitiveRelativeWeights2", () => { const match1 = getFirstMatch("BazBarFooFooFoo", "FFF"); const match2 = getFirstMatch("BazFogBarFooFoo", "FFF"); // Contiguous things should also be preferred assertInRange(match1.camelCaseWeight, match2.camelCaseWeight + 1, 1 << 30); }); it("PreferCaseSensitiveRelativeWeights3", () => { const match1 = getFirstMatch("FogBarFooFoo", "FFF"); const match2 = getFirstMatch("BarFooFooFoo", "FFF"); // The weight of being first should be greater than the weight of being contiguous assertInRange(match1.camelCaseWeight, match2.camelCaseWeight + 1, 1 << 30); }); it("AllLowerPattern1", () => { const match = getFirstMatch("FogBarChangedEventArgs", "changedeventargs"); assert.isTrue(undefined !== match); }); it("AllLowerPattern2", () => { const match = getFirstMatch("FogBarChangedEventArgs", "changedeventarrrgh"); assert.isTrue(undefined === match); }); it("AllLowerPattern3", () => { const match = getFirstMatch("ABCDEFGH", "bcd"); assert.isTrue(undefined !== match); }); it("AllLowerPattern4", () => { const match = getFirstMatch("AbcdefghijEfgHij", "efghij"); assert.isTrue(undefined === match); }); }); describe("MultiWordPattern", () => { it("ExactWithLowercase", () => { const matches = getAllMatches("AddMetadataReference", "addmetadatareference"); assertContainsKind(ts.PatternMatchKind.exact, matches); }); it("SingleLowercasedSearchWord1", () => { const matches = getAllMatches("AddMetadataReference", "add"); assertContainsKind(ts.PatternMatchKind.prefix, matches); }); it("SingleLowercasedSearchWord2", () => { const matches = getAllMatches("AddMetadataReference", "metadata"); assertContainsKind(ts.PatternMatchKind.substring, matches); }); it("SingleUppercaseSearchWord1", () => { const matches = getAllMatches("AddMetadataReference", "Add"); assertContainsKind(ts.PatternMatchKind.prefix, matches); }); it("SingleUppercaseSearchWord2", () => { const matches = getAllMatches("AddMetadataReference", "Metadata"); assertContainsKind(ts.PatternMatchKind.substring, matches); }); it("SingleUppercaseSearchLetter1", () => { const matches = getAllMatches("AddMetadataReference", "A"); assertContainsKind(ts.PatternMatchKind.prefix, matches); }); it("SingleUppercaseSearchLetter2", () => { const matches = getAllMatches("AddMetadataReference", "M"); assertContainsKind(ts.PatternMatchKind.substring, matches); }); it("TwoLowercaseWords", () => { const matches = getAllMatches("AddMetadataReference", "add metadata"); assertContainsKind(ts.PatternMatchKind.prefix, matches); assertContainsKind(ts.PatternMatchKind.substring, matches); }); it("TwoLowercaseWords", () => { const matches = getAllMatches("AddMetadataReference", "A M"); assertContainsKind(ts.PatternMatchKind.prefix, matches); assertContainsKind(ts.PatternMatchKind.substring, matches); }); it("TwoLowercaseWords", () => { const matches = getAllMatches("AddMetadataReference", "AM"); assertContainsKind(ts.PatternMatchKind.camelCase, matches); }); it("TwoLowercaseWords", () => { const matches = getAllMatches("AddMetadataReference", "ref Metadata"); assertArrayEquals(ts.map(matches, m => m.kind), [ts.PatternMatchKind.substring, ts.PatternMatchKind.substring]); }); it("TwoLowercaseWords", () => { const matches = getAllMatches("AddMetadataReference", "ref M"); assertArrayEquals(ts.map(matches, m => m.kind), [ts.PatternMatchKind.substring, ts.PatternMatchKind.substring]); }); it("MixedCamelCase", () => { const matches = getAllMatches("AddMetadataReference", "AMRe"); assertContainsKind(ts.PatternMatchKind.camelCase, matches); }); it("BlankPattern", () => { const matches = getAllMatches("AddMetadataReference", ""); assert.isTrue(matches === undefined); }); it("WhitespaceOnlyPattern", () => { const matches = getAllMatches("AddMetadataReference", " "); assert.isTrue(matches === undefined); }); it("EachWordSeparately1", () => { const matches = getAllMatches("AddMetadataReference", "add Meta"); assertContainsKind(ts.PatternMatchKind.prefix, matches); assertContainsKind(ts.PatternMatchKind.substring, matches); }); it("EachWordSeparately2", () => { const matches = getAllMatches("AddMetadataReference", "Add meta"); assertContainsKind(ts.PatternMatchKind.prefix, matches); assertContainsKind(ts.PatternMatchKind.substring, matches); }); it("EachWordSeparately3", () => { const matches = getAllMatches("AddMetadataReference", "Add Meta"); assertContainsKind(ts.PatternMatchKind.prefix, matches); assertContainsKind(ts.PatternMatchKind.substring, matches); }); it("MixedCasing", () => { const matches = getAllMatches("AddMetadataReference", "mEta"); assert.isTrue(matches === undefined); }); it("MixedCasing2", () => { const matches = getAllMatches("AddMetadataReference", "Data"); assert.isTrue(matches === undefined); }); it("AsteriskSplit", () => { const matches = getAllMatches("GetKeyWord", "K*W"); assertArrayEquals(ts.map(matches, m => m.kind), [ts.PatternMatchKind.substring, ts.PatternMatchKind.substring]); }); it("LowercaseSubstring1", () => { const matches = getAllMatches("Operator", "a"); assert.isTrue(matches === undefined); }); it("LowercaseSubstring2", () => { const matches = getAllMatches("FooAttribute", "a"); assertContainsKind(ts.PatternMatchKind.substring, matches); assert.isFalse(matches[0].isCaseSensitive); }); }); describe("DottedPattern", () => { it("DottedPattern1", () => { const match = getFirstMatchForDottedPattern("Foo.Bar.Baz", "Quux", "B.Q"); assert.equal(ts.PatternMatchKind.prefix, match.kind); assert.equal(true, match.isCaseSensitive); }); it("DottedPattern2", () => { const match = getFirstMatchForDottedPattern("Foo.Bar.Baz", "Quux", "C.Q"); assert.isTrue(match === undefined); }); it("DottedPattern3", () => { const match = getFirstMatchForDottedPattern("Foo.Bar.Baz", "Quux", "B.B.Q"); assert.equal(ts.PatternMatchKind.prefix, match.kind); assert.equal(true, match.isCaseSensitive); }); it("DottedPattern4", () => { const match = getFirstMatchForDottedPattern("Foo.Bar.Baz", "Quux", "Baz.Quux"); assert.equal(ts.PatternMatchKind.exact, match.kind); assert.equal(true, match.isCaseSensitive); }); it("DottedPattern5", () => { const match = getFirstMatchForDottedPattern("Foo.Bar.Baz", "Quux", "F.B.B.Quux"); assert.equal(ts.PatternMatchKind.exact, match.kind); assert.equal(true, match.isCaseSensitive); }); it("DottedPattern6", () => { const match = getFirstMatchForDottedPattern("Foo.Bar.Baz", "Quux", "F.F.B.B.Quux"); assert.isTrue(match === undefined); }); it("DottedPattern7", () => { let match = getFirstMatch("UIElement", "UIElement"); match = getFirstMatch("GetKeyword", "UIElement"); assert.isTrue(match === undefined); }); }); function getFirstMatch(candidate: string, pattern: string): ts.PatternMatch { const matches = ts.createPatternMatcher(pattern).getMatchesForLastSegmentOfPattern(candidate); return matches ? matches[0] : undefined; } function getAllMatches(candidate: string, pattern: string): ts.PatternMatch[] { return ts.createPatternMatcher(pattern).getMatchesForLastSegmentOfPattern(candidate); } function getFirstMatchForDottedPattern(dottedContainer: string, candidate: string, pattern: string): ts.PatternMatch { const matches = ts.createPatternMatcher(pattern).getMatches(dottedContainer.split("."), candidate); return matches ? matches[0] : undefined; } function spanListToSubstrings(identifier: string, spans: ts.TextSpan[]) { return ts.map(spans, s => identifier.substr(s.start, s.length)); } function breakIntoCharacterSpans(identifier: string) { return spanListToSubstrings(identifier, ts.breakIntoCharacterSpans(identifier)); } function breakIntoWordSpans(identifier: string) { return spanListToSubstrings(identifier, ts.breakIntoWordSpans(identifier)); } function assertArrayEquals(array1: T[], array2: T[]) { assert.equal(array1.length, array2.length); for (let i = 0, n = array1.length; i < n; i++) { assert.equal(array1[i], array2[i]); } } function assertInRange(val: number, low: number, high: number) { assert.isTrue(val >= low); assert.isTrue(val <= high); } function verifyBreakIntoCharacterSpans(original: string, ...parts: string[]): void { assertArrayEquals(parts, breakIntoCharacterSpans(original)); } function verifyBreakIntoWordSpans(original: string, ...parts: string[]): void { assertArrayEquals(parts, breakIntoWordSpans(original)); } function assertContainsKind(kind: ts.PatternMatchKind, results: ts.PatternMatch[]) { assert.isTrue(ts.forEach(results, r => r.kind === kind)); } });