Files
RobustToolbox/Robust.Analyzers.Tests/HasDependenciesGeneratorTest.cs

319 lines
10 KiB
C#

extern alias SerializationGenerator;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using NUnit.Framework;
using Robust.Analyzers.Generators;
namespace Robust.Analyzers.Tests;
[TestFixture]
[TestOf(typeof(HasDependenciesGenerator))]
[Parallelizable(ParallelScope.All)]
public sealed class HasDependenciesGeneratorTest
{
[Test]
public void TestBasic()
{
var result = RunGenerator("""
using Robust.Shared.IoC;
public sealed partial class Foobar
{
[Dependency]
public string Foo;
}
""");
ExpectNoDiagnostics(result);
ExpectSource(
result,
"""
// <auto-generated />
[global::Robust.Shared.IoC.HasDependenciesGeneratedAttribute]
public partial class Foobar : global::Robust.Shared.IoC.IHasDependencies
{
[global::Robust.Shared.Analyzers.RobustAutoGenerated]
void global::Robust.Shared.IoC.IHasDependencies.Inject(global::Robust.Shared.IoC.IDependencyCollection dependencies)
{
Foo = dependencies.ResolveInject<global::string>(typeof(Foobar));
}
}
""");
}
[Test]
public void TestInheritGeneric()
{
var result = RunGenerator("""
using Robust.Shared.IoC;
public partial class Foo<T>
{
[Dependency] string _x = null!;
}
public sealed partial class Bar : Foo<int>
{
[Dependency]
public string _heck = null!;
}
""");
ExpectNoDiagnostics(result);
Assert.That(result.GeneratedSources, Has.Length.EqualTo(2));
ExpectNamedSource(
result,
"Foo`1.g.cs",
"""
// <auto-generated />
[global::Robust.Shared.IoC.HasDependenciesGeneratedAttribute]
public partial class Foo<T> : global::Robust.Shared.IoC.IHasDependencies
{
[global::Robust.Shared.Analyzers.RobustAutoGenerated]
void global::Robust.Shared.IoC.IHasDependencies.Inject(global::Robust.Shared.IoC.IDependencyCollection dependencies)
{
InjectImpl(dependencies);
}
[global::Robust.Shared.Analyzers.RobustAutoGenerated]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected virtual void InjectImpl(global::Robust.Shared.IoC.IDependencyCollection dependencies)
{
_x = dependencies.ResolveInject<global::string>(typeof(Foo<T>));
}
}
""");
ExpectNamedSource(
result,
"Bar.g.cs",
"""
// <auto-generated />
[global::Robust.Shared.IoC.HasDependenciesGeneratedAttribute]
public partial class Bar
{
[global::Robust.Shared.Analyzers.RobustAutoGenerated]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected override void InjectImpl(global::Robust.Shared.IoC.IDependencyCollection dependencies)
{
_heck = dependencies.ResolveInject<global::string>(typeof(Bar));
base.InjectImpl(dependencies);
}
}
""");
}
[Test]
public void TestGenericInherit()
{
var result = RunGenerator("""
using Robust.Shared.IoC;
public partial class Foo
{
[Dependency] string _x = null!;
}
public sealed partial class Bar<T> : Foo
{
[Dependency]
public string _heck = null!;
}
""");
ExpectNoDiagnostics(result);
Assert.That(result.GeneratedSources, Has.Length.EqualTo(2));
ExpectNamedSource(
result,
"Foo.g.cs",
"""
// <auto-generated />
[global::Robust.Shared.IoC.HasDependenciesGeneratedAttribute]
public partial class Foo : global::Robust.Shared.IoC.IHasDependencies
{
[global::Robust.Shared.Analyzers.RobustAutoGenerated]
void global::Robust.Shared.IoC.IHasDependencies.Inject(global::Robust.Shared.IoC.IDependencyCollection dependencies)
{
InjectImpl(dependencies);
}
[global::Robust.Shared.Analyzers.RobustAutoGenerated]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected virtual void InjectImpl(global::Robust.Shared.IoC.IDependencyCollection dependencies)
{
_x = dependencies.ResolveInject<global::string>(typeof(Foo));
}
}
""");
ExpectNamedSource(
result,
"Bar`1.g.cs",
"""
// <auto-generated />
[global::Robust.Shared.IoC.HasDependenciesGeneratedAttribute]
public partial class Bar<T>
{
[global::Robust.Shared.Analyzers.RobustAutoGenerated]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected override void InjectImpl(global::Robust.Shared.IoC.IDependencyCollection dependencies)
{
_heck = dependencies.ResolveInject<global::string>(typeof(Bar<T>));
base.InjectImpl(dependencies);
}
}
""");
}
[Test]
public void TestReadOnly()
{
var result = RunGenerator("""
using Robust.Shared.IoC;
public sealed partial class Foobar
{
[Dependency]
public readonly string Foo;
}
""");
ExpectNoDiagnostics(result);
ExpectNoSource(result);
}
[Test]
public void TestNotPartial()
{
var result = RunGenerator("""
using Robust.Shared.IoC;
public sealed class Foobar
{
[Dependency]
public string Foo;
}
""");
ExpectNoDiagnostics(result);
ExpectNoSource(result);
}
[Test]
public void TestNested()
{
var result = RunGenerator("""
using Robust.Shared.IoC;
public sealed partial class Real
{
public sealed partial class Foobar
{
[Dependency]
public string Foo;
}
}
""");
ExpectNoDiagnostics(result);
ExpectSource(
result,
"""
// <auto-generated />
public partial class Real
{
[global::Robust.Shared.IoC.HasDependenciesGeneratedAttribute]
public partial class Foobar : global::Robust.Shared.IoC.IHasDependencies
{
[global::Robust.Shared.Analyzers.RobustAutoGenerated]
void global::Robust.Shared.IoC.IHasDependencies.Inject(global::Robust.Shared.IoC.IDependencyCollection dependencies)
{
Foo = dependencies.ResolveInject<global::string>(typeof(Real.Foobar));
}
}
}
""");
}
private static void ExpectSource(GeneratorRunResult result, string expected)
{
Assert.That(result.GeneratedSources, Has.Length.EqualTo(1));
var source = result.GeneratedSources[0];
Assert.That(source.SourceText.ToString().ReplaceLineEndings(), Is.EqualTo(expected.ReplaceLineEndings()));
}
private static void ExpectNamedSource(GeneratorRunResult result, string name, string expected)
{
var source = result.GeneratedSources.Single(s => s.HintName == name);
Assert.That(source.SourceText.ToString().ReplaceLineEndings(), Is.EqualTo(expected.ReplaceLineEndings()));
}
private static void ExpectNoSource(GeneratorRunResult result)
{
Assert.That(result.GeneratedSources, Is.Empty);
}
private static void ExpectNoDiagnostics(GeneratorRunResult result)
{
Assert.That(result.Diagnostics, Is.Empty);
}
private static void ExpectDiagnostics(GeneratorRunResult result, (string code, LinePositionSpan span)[] diagnostics)
{
Assert.Multiple(() =>
{
Assert.That(result.Diagnostics, Has.Length.EqualTo(diagnostics.Length));
foreach (var (code, span) in diagnostics)
{
Assert.That(
result.Diagnostics.Any(x => x.Id == code && x.Location.GetLineSpan().Span == span),
$"Expected diagnostic with code {code} and location {span}");
}
});
}
private static GeneratorRunResult RunGenerator(string source)
{
var compilation = (Compilation)CSharpCompilation.Create("compilation",
[
CSharpSyntaxTree.ParseText(source, path: "Source.cs"),
..TestHelper.GetEmbeddedSyntaxTrees(
"Robust.Shared.IoC.DependencyAttribute.cs",
"Robust.Shared.IoC.IHasDependencies.cs"),
],
new[] { MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location) },
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
var generator = new HasDependenciesGenerator();
GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out var newCompilation, out _);
var result = driver.GetRunResult();
return result.Results[0];
}
}