/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Features/Test/NavigateTo/RegexDetectionTests.cs
247 строк
7 KB
Cyrus Najmabadi
Make Compile return null when no literals; tighten contracts
12 мар 2026, 18:59
12 мар 2026, 18:59
1ee7160
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Text.RegularExpressions; using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.NavigateTo; using Xunit; namespace Microsoft.CodeAnalysis.UnitTests.NavigateTo; public sealed class RegexDetectionTests { private static (string? container, string name) SplitOnContainerDot(string pattern) { var sequence = VirtualCharSequence.Create(0, pattern); var tree = RegexParser.TryParse(sequence, RegexOptions.None); if (tree is not { Diagnostics: [] }) return (null, pattern); return RegexPatternDetector.SplitOnContainerDot(pattern, tree); } #region IsRegexPattern — positive (is regex) [Theory] [InlineData("(Read|Write)")] [InlineData("Read|Write")] [InlineData("[abc]")] [InlineData("Goo.*Bar")] [InlineData("Goo.+Bar")] [InlineData("x+")] [InlineData("x?")] [InlineData("x*")] [InlineData(@"a\d")] [InlineData("^Start")] [InlineData("End$")] [InlineData("a{2,3}")] [InlineData("a{2}")] [InlineData(@"Goo\.Bar")] [InlineData("(Read|Write)Line")] [InlineData("(?:abc)")] public void IsRegexPattern_Positive(string pattern) { Assert.True(RegexPatternDetector.IsRegexPattern(pattern)); } #endregion #region IsRegexPattern — negative (not regex) [Theory] [InlineData("abc")] [InlineData("GooBar")] [InlineData("x.y")] [InlineData("Goo.Bar.Baz")] [InlineData("get word")] [InlineData("ReadLine")] [InlineData("_myField")] [InlineData("System.IO.File")] [InlineData("")] [InlineData("a")] public void IsRegexPattern_Negative(string pattern) { Assert.False(RegexPatternDetector.IsRegexPattern(pattern)); } #endregion #region SplitOnContainerDot — positive (split occurs) [Fact] public void Split_PlainGooDotBar() { // Goo.Bar -> bare dot splits into container="Goo", name="Bar" var (container, name) = SplitOnContainerDot("Goo.Bar"); Assert.Equal("Goo", container); Assert.Equal("Bar", name); } [Fact] public void Split_RegexContainerPlainName() { // (Goo|Bar).Baz -> bare dot after ')' -> container="(Goo|Bar)", name="Baz" var (container, name) = SplitOnContainerDot("(Goo|Bar).Baz"); Assert.Equal("(Goo|Bar)", container); Assert.Equal("Baz", name); } [Fact] public void Split_RegexContainerRegexName() { // (Goo|Bar).(Baz|Quux) -> bare dot -> container="(Goo|Bar)", name="(Baz|Quux)" var (container, name) = SplitOnContainerDot("(Goo|Bar).(Baz|Quux)"); Assert.Equal("(Goo|Bar)", container); Assert.Equal("(Baz|Quux)", name); } [Fact] public void Split_MultipleDots_SplitsOnLast() { // System.IO.File -> last bare dot is before "File" var (container, name) = SplitOnContainerDot("System.IO.File"); Assert.Equal("System.IO", container); Assert.Equal("File", name); } [Fact] public void Split_RegexContainerWithMultipleDots() { // System.(IO|Net).File -> last bare dot is before "File" var (container, name) = SplitOnContainerDot("System.(IO|Net).File"); Assert.Equal("System.(IO|Net)", container); Assert.Equal("File", name); } [Fact] public void Split_ReadDotLine() { // Read.Line -> bare dot splits var (container, name) = SplitOnContainerDot("Read.Line"); Assert.Equal("Read", container); Assert.Equal("Line", name); } #endregion #region SplitOnContainerDot — negative (no split) [Fact] public void NoSplit_GooDotStarBar() { // Goo.*Bar -> the dot is quantified with *, not bare -> no split var (container, name) = SplitOnContainerDot("Goo.*Bar"); Assert.Null(container); Assert.Equal("Goo.*Bar", name); } [Fact] public void NoSplit_GooDotPlusBar() { // Goo.+Bar -> the dot is quantified with +, not bare -> no split var (container, name) = SplitOnContainerDot("Goo.+Bar"); Assert.Null(container); Assert.Equal("Goo.+Bar", name); } [Fact] public void NoSplit_EscapedDot() { // Goo\.Bar -> escape node, not a wildcard -> no split var (container, name) = SplitOnContainerDot(@"Goo\.Bar"); Assert.Null(container); Assert.Equal(@"Goo\.Bar", name); } [Fact] public void NoSplit_NoDotAtAll() { // (Read|Write)Line -> no dot at all var (container, name) = SplitOnContainerDot("(Read|Write)Line"); Assert.Null(container); Assert.Equal("(Read|Write)Line", name); } [Fact] public void NoSplit_PlainTextNoDot() { var (container, name) = SplitOnContainerDot("ReadLine"); Assert.Null(container); Assert.Equal("ReadLine", name); } [Fact] public void NoSplit_TopLevelAlternation() { // Goo.Bar|Baz.Quux -> top-level alternation has two branches; dot is inside a branch, not top-level var (container, name) = SplitOnContainerDot("Goo.Bar|Baz.Quux"); Assert.Null(container); Assert.Equal("Goo.Bar|Baz.Quux", name); } [Fact] public void NoSplit_DotQuestionBar() { // Goo.?Bar -> the dot is quantified with ? -> no split var (container, name) = SplitOnContainerDot("Goo.?Bar"); Assert.Null(container); Assert.Equal("Goo.?Bar", name); } [Fact] public void NoSplit_InvalidRegex() { // Unbalanced parens -> parser returns diagnostics -> no split, return as-is var (container, name) = SplitOnContainerDot("(Goo.Bar"); Assert.Null(container); Assert.Equal("(Goo.Bar", name); } [Fact] public void NoSplit_EmptyPattern() { var (container, name) = SplitOnContainerDot(""); Assert.Null(container); Assert.Equal("", name); } [Fact] public void NoSplit_DotAtStart() { // .Goo -> the bare dot is at position 0, so containerEnd == 0 -> skip it var (container, name) = SplitOnContainerDot(".Goo"); Assert.Null(container); Assert.Equal(".Goo", name); } [Fact] public void NoSplit_DotAtEnd() { // Goo. -> the bare dot is at the last position, so nameStart >= pattern.Length -> skip it var (container, name) = SplitOnContainerDot("Goo."); Assert.Null(container); Assert.Equal("Goo.", name); } [Fact] public void Split_DotAtStartAndMiddle_SplitsOnMiddle() { // .Goo.Bar -> leading dot is skipped (containerEnd == 0), middle dot splits var (container, name) = SplitOnContainerDot(".Goo.Bar"); Assert.Equal(".Goo", container); Assert.Equal("Bar", name); } [Fact] public void Split_DotAtMiddleAndEnd_SplitsOnMiddle() { // Goo.Bar. -> trailing dot is skipped (nameStart >= Length), middle dot splits var (container, name) = SplitOnContainerDot("Goo.Bar."); Assert.Equal("Goo", container); Assert.Equal("Bar.", name); } #endregion }