Skip to content

Commit

Permalink
Merge pull request #64420 from CyrusNajmabadi/addSymbolKeyTests
Browse files Browse the repository at this point in the history
Add symbol key tests
  • Loading branch information
CyrusNajmabadi committed Oct 7, 2022
2 parents f13d4db + afa2941 commit ef1adec
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/Workspaces/Core/Portable/Remote/RemoteArguments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public static bool TryCreate(
try
{
throw new InvalidOperationException(
$"We should always be able to resolve a symbol back on the host side:\r\n{project.Name}\r\n{SymbolKeyData}\r\n{failureReason}");
$"We should always be able to resolve a symbol back on the host side:\r\n'{project.Name}-{project.Language}'\r\n'{SymbolKeyData}'\r\n'{failureReason}'");
}
catch (Exception ex) when (FatalError.ReportAndCatch(ex))
{
Expand Down
187 changes: 187 additions & 0 deletions src/Workspaces/CoreTest/SymbolKeyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,176 @@ public class B { };
TestRoundTrip(GetDeclaredSymbols(compilation), compilation);
}

[Fact]
public void TestMissingField1_CSharp()
{
var source = @"
public class C
{
const int;
}
";
var compilation = GetCompilation(source, LanguageNames.CSharp);
var symbols = GetDeclaredSymbols(compilation);
Assert.True(symbols.Any(s => s is IFieldSymbol { MetadataName: "" }));
TestRoundTrip(symbols, compilation);
}

[Fact]
public void TestMissingField2_CSharp()
{
var source = @"
public class C
{
int a,;
}
";
var compilation = GetCompilation(source, LanguageNames.CSharp);
var symbols = GetDeclaredSymbols(compilation);
Assert.True(symbols.Any(s => s is IFieldSymbol { MetadataName: "" }));
TestRoundTrip(symbols, compilation);
}

[Fact]
public void TestMissingField3_CSharp()
{
var source = @"
public class C
{
const;
}
";
var compilation = GetCompilation(source, LanguageNames.CSharp);
var symbols = GetDeclaredSymbols(compilation);
Assert.True(symbols.Any(s => s is IFieldSymbol { MetadataName: "" }));
TestRoundTrip(symbols, compilation);
}

[Fact]
public void TestMissingField1_VisualBasic()
{
var source = @"
public class C
constant as integer
end class
";
var compilation = GetCompilation(source, LanguageNames.VisualBasic);
var symbols = GetDeclaredSymbols(compilation);
Assert.False(symbols.Any(s => s is IFieldSymbol { MetadataName: "" }));
TestRoundTrip(symbols, compilation);
}

[Fact]
public void TestMissingField2_VisualBasic()
{
var source = @"
public class C
dim a,
end class
";
var compilation = GetCompilation(source, LanguageNames.VisualBasic);
var symbols = GetDeclaredSymbols(compilation);
Assert.True(symbols.Any(s => s is IFieldSymbol { MetadataName: "" }));
TestRoundTrip(symbols, compilation);
}

[Fact]
public void TestMissingField3_VisualBasic()
{
var source = @"
public class C
dim a, as integer
end class
";
var compilation = GetCompilation(source, LanguageNames.VisualBasic);
var symbols = GetDeclaredSymbols(compilation);
Assert.False(symbols.Any(s => s is IFieldSymbol { MetadataName: "" }));
TestRoundTrip(symbols, compilation);
}

[Fact]
public void TestMissingField4_VisualBasic()
{
var source = @"
public class C
dim a as integer,
end class
";
var compilation = GetCompilation(source, LanguageNames.VisualBasic);
var symbols = GetDeclaredSymbols(compilation);
Assert.True(symbols.Any(s => s is IFieldSymbol { MetadataName: "" }));
TestRoundTrip(symbols, compilation);
}

[Fact]
public void TestMissingField5_VisualBasic()
{
var source = @"
public class C
constant
end class
";
var compilation = GetCompilation(source, LanguageNames.VisualBasic);
var symbols = GetDeclaredSymbols(compilation);
Assert.False(symbols.Any(s => s is IFieldSymbol { MetadataName: "" }));
TestRoundTrip(symbols, compilation);
}

[Fact]
public void TestMissingField6_VisualBasic()
{
var source = @"
public class C
constant a,
end class
";
var compilation = GetCompilation(source, LanguageNames.VisualBasic);
var symbols = GetDeclaredSymbols(compilation);
Assert.True(symbols.Any(s => s is IFieldSymbol { MetadataName: "" }));
TestRoundTrip(symbols, compilation);
}

[Fact]
public void TestMissingEvent1_CSharp()
{
var source = @"
public class C
{
event System.Action;
}
";
var compilation = GetCompilation(source, LanguageNames.CSharp);
var symbols = GetDeclaredSymbols(compilation);
Assert.True(symbols.Any(s => s is IEventSymbol { MetadataName: "" }));
TestRoundTrip(symbols, compilation);
}

[Fact]
public void TestMissingEvent2_CSharp()
{
var source = @"
public class C
{
event System.Action a,;
}
";
var compilation = GetCompilation(source, LanguageNames.CSharp);
var symbols = GetDeclaredSymbols(compilation);
Assert.True(symbols.Any(s => s is IEventSymbol { MetadataName: "" }));
TestRoundTrip(symbols, compilation);
}

[Fact, WorkItem(14364, "https://github.com/dotnet/roslyn/issues/14364")]
public void TestVBParameterizedEvent()
{
Expand Down Expand Up @@ -1063,6 +1233,23 @@ public Goo<X> G() { }
}
}

[Fact]
public void TestCrossLanguageEquality1()
{
var compilation1 = GetCompilation("", LanguageNames.CSharp);
var compilation2 = GetCompilation("", LanguageNames.VisualBasic);

var symbolKey1 = SymbolKey.Create(compilation1.GetSpecialType(SpecialType.System_Int32));
var symbolKey2 = SymbolKey.Create(compilation2.GetSpecialType(SpecialType.System_Int32));

Assert.NotEqual(symbolKey1.ToString(), symbolKey2.ToString());

Assert.True(symbolKey1.Equals(symbolKey2));
Assert.True(SymbolKey.GetComparer(ignoreCase: true).Equals(symbolKey1, symbolKey2));
Assert.True(SymbolKey.GetComparer(ignoreAssemblyKeys: true).Equals(symbolKey1, symbolKey2));
Assert.True(SymbolKey.GetComparer(ignoreCase: true, ignoreAssemblyKeys: true).Equals(symbolKey1, symbolKey2));
}

private static void TestRoundTrip(IEnumerable<ISymbol> symbols, Compilation compilation, Func<ISymbol, object> fnId = null)
{
foreach (var symbol in symbols)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,23 @@ private SymbolKeyComparer(ComparisonOptions options)

public bool Equals(SymbolKey x, SymbolKey y)
{
var comparer = _options.IgnoreCase
? StringComparer.OrdinalIgnoreCase
: StringComparer.Ordinal;

if (!_options.IgnoreAssemblyKey)
{
// Easiest case. We can directly compare the raw contents of the keys.
return comparer.Equals(x._symbolKeyData, y._symbolKeyData);
return x.Equals(y, _options.IgnoreCase);
}
else
{
// This is harder. To compare these we need to remove the entries related to
// assemblies.
// This is harder. To compare these we need to remove the entries related to assemblies.
//
// Note: this will remove the language-string as well, so we don't have to worry about that here.
var data1 = RemoveAssemblyKeys(x._symbolKeyData);
var data2 = RemoveAssemblyKeys(y._symbolKeyData);

var comparer = _options.IgnoreCase
? StringComparer.OrdinalIgnoreCase
: StringComparer.Ordinal;

return comparer.Equals(data1, data2);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@ public void Initialize(string data)

public string RemoveAssemblySymbolKeys()
{
this.ReadFormatVersion();

// read out the language as well, it's not part of any symbol key comparison
this.SkipString();

while (Position < Data.Length)
{
var ch = Data[Position];
Expand All @@ -260,15 +265,9 @@ public string RemoveAssemblySymbolKeys()

var type = (SymbolKeyType)Data[Position];
_builder.Append(Eat(type));
if (type == SymbolKeyType.Assembly)
{
Debug.Assert(_skipString == false);
_skipString = true;
ReadString();

Debug.Assert(_skipString == true);
_skipString = false;
}
if (type == SymbolKeyType.Assembly)
SkipString();
}
else if (Data[Position] == DoubleQuoteChar)
{
Expand All @@ -284,6 +283,17 @@ public string RemoveAssemblySymbolKeys()
return _builder.ToString();
}

private void SkipString()
{
Debug.Assert(_skipString == false);
_skipString = true;

ReadString();

Debug.Assert(_skipString == true);
_skipString = false;
}

protected override object? CreateResultForString(int start, int end, bool hasEmbeddedQuote)
{
// 'start' is right after the open quote, and 'end' is right before the close quote.
Expand Down
Loading

0 comments on commit ef1adec

Please sign in to comment.