-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Set up logic for automatically generating interfaces for types, since…
… I've been having trouble with my existing library I used.
- Loading branch information
1 parent
1b521be
commit eaee2ca
Showing
8 changed files
with
1,084 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
using NUnit.Framework; | ||
|
||
using schema.binary; | ||
|
||
|
||
namespace schema.autoInterface; | ||
|
||
internal class ConstraintTests { | ||
[Test] | ||
[TestCase("class")] | ||
[TestCase("class?")] | ||
[TestCase("notnull")] | ||
[TestCase("struct")] | ||
[TestCase("unmanaged")] | ||
[TestCase("System.IO.Stream")] | ||
[TestCase("System.Collections.Generic.IEnumerable<T>")] | ||
public void TestEachConstraintType(string constraint) { | ||
InterfaceGeneratorTestUtil.AssertGenerated( | ||
$$""" | ||
using schema.autoInterface; | ||
|
||
namespace foo.bar { | ||
[GenerateInterface] | ||
public partial class EachConstraint<T> where T : {{constraint}} { | ||
public T Foo<S>(T t, S s) where S : {{constraint}} { } | ||
} | ||
} | ||
""", | ||
$$""" | ||
namespace foo.bar { | ||
public partial class EachConstraint<T> : IEachConstraint<T>; | ||
|
||
#nullable enable | ||
public interface IEachConstraint<T> where T : {{constraint}} { | ||
public T Foo<S>(T t, S s) where S : {{constraint}}; | ||
} | ||
} | ||
|
||
"""); | ||
} | ||
|
||
[Test] | ||
public void TestCircularConstraints() { | ||
InterfaceGeneratorTestUtil.AssertGenerated( | ||
""" | ||
using schema.autoInterface; | ||
|
||
namespace build.autoInterface { | ||
[GenerateInterface] | ||
public partial class Circular<[KeepMutableType] TMutable, TInterface, TImpl> | ||
where TMutable : Circular<TMutable, TInterface, TImpl>, TInterface | ||
where TInterface : ICircular<TMutable, TInterface, TImpl> { | ||
public TMutable Foo(TInterface other); | ||
|
||
public TMutable Foo(in TImpl other); | ||
} | ||
} | ||
""", | ||
""" | ||
namespace build.autoInterface { | ||
public partial class Circular<TMutable, TInterface, TImpl> : ICircular<TMutable, TInterface, TImpl>; | ||
|
||
#nullable enable | ||
public interface ICircular<TMutable, TInterface, TImpl> where TMutable : Circular<TMutable, TInterface, TImpl>, TInterface where TInterface : build.autoInterface.ICircular<TMutable, TInterface, TImpl> { | ||
public TMutable Foo(TInterface other); | ||
public TMutable Foo(in TImpl other); | ||
} | ||
} | ||
|
||
"""); | ||
} | ||
|
||
[Test] | ||
public void TestGenericSubConstraint() { | ||
InterfaceGeneratorTestUtil.AssertGenerated( | ||
""" | ||
using schema.autoInterface; | ||
|
||
namespace foo.bar { | ||
[GenerateInterface] | ||
public partial class SubConstraint<T1, T2> where T2 : T1 { | ||
public T1 Foo<S>(S s) where S : T1 { } | ||
|
||
public T2 Bar { get; set; } | ||
} | ||
} | ||
""", | ||
""" | ||
namespace foo.bar { | ||
public partial class SubConstraint<T1, T2> : ISubConstraint<T1, T2>; | ||
|
||
#nullable enable | ||
public interface ISubConstraint<T1, T2> where T2 : T1 { | ||
public T1 Foo<S>(S s) where S : T1; | ||
public T2 Bar { get; set; } | ||
} | ||
} | ||
|
||
"""); | ||
} | ||
|
||
[Test] | ||
public void TestMultipleGenericConstraints() { | ||
InterfaceGeneratorTestUtil.AssertGenerated( | ||
""" | ||
using schema.autoInterface; | ||
|
||
namespace foo.bar { | ||
[GenerateInterface] | ||
public partial class SimpleAttributes<T1, T2> where T1 : notnull, struct where T2 : unmanaged { | ||
public T1 Foo<T3, T4>(T1 t1, T2 t2, T3 t3, T4 t4) where T3 : class where T4 : class? { } | ||
|
||
public T2 Bar { get; set; } | ||
} | ||
} | ||
""", | ||
""" | ||
namespace foo.bar { | ||
public partial class SimpleAttributes<T1, T2> : ISimpleAttributes<T1, T2>; | ||
|
||
#nullable enable | ||
public interface ISimpleAttributes<T1, T2> where T1 : notnull, struct where T2 : unmanaged { | ||
public T1 Foo<T3, T4>(T1 t1, T2 t2, T3 t3, T4 t4) where T3 : class where T4 : class?; | ||
public T2 Bar { get; set; } | ||
} | ||
} | ||
|
||
"""); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
using NUnit.Framework; | ||
|
||
using schema.binary; | ||
|
||
|
||
namespace schema.autoInterface; | ||
|
||
internal class DefaultValueTests { | ||
[Test] | ||
[TestCase("null")] | ||
[TestCase("false")] | ||
[TestCase("true")] | ||
public void TestSupportsDefaultBools(string boolValue) { | ||
InterfaceGeneratorTestUtil.AssertGenerated( | ||
$$""" | ||
using schema.autoInterface; | ||
|
||
namespace foo.bar { | ||
[GenerateInterface] | ||
public partial class Wrapper { | ||
[Const] | ||
public void Foo(bool? value = {{boolValue}}); | ||
} | ||
} | ||
""", | ||
$$""" | ||
namespace foo.bar { | ||
public partial class Wrapper : IWrapper; | ||
|
||
#nullable enable | ||
public interface IWrapper { | ||
public void Foo(bool? value = {{boolValue}}); | ||
} | ||
} | ||
|
||
"""); | ||
} | ||
|
||
[Test] | ||
[TestCase("null")] | ||
[TestCase("0")] | ||
[TestCase("-123")] | ||
[TestCase("123")] | ||
public void TestSupportsDefaultInts(string intValue) { | ||
InterfaceGeneratorTestUtil.AssertGenerated( | ||
$$""" | ||
using schema.autoInterface; | ||
|
||
namespace foo.bar { | ||
[GenerateInterface] | ||
public partial class Wrapper { | ||
[Const] | ||
public void Foo(int? value = {{intValue}}); | ||
} | ||
} | ||
""", | ||
$$""" | ||
namespace foo.bar { | ||
public partial class Wrapper : IWrapper; | ||
|
||
#nullable enable | ||
public interface IWrapper { | ||
public void Foo(int? value = {{intValue}}); | ||
} | ||
} | ||
|
||
"""); | ||
} | ||
|
||
[Test] | ||
[TestCase("null", "null")] | ||
[TestCase("SomeType.FOO", "(other.SomeType) 123")] | ||
public void | ||
TestSupportsDefaultEnums(string enumValue, string readonlyValue) { | ||
InterfaceGeneratorTestUtil.AssertGenerated( | ||
$$""" | ||
using schema.autoInterface; | ||
using foo.bar.other; | ||
|
||
namespace foo.bar.other { | ||
public enum SomeType { | ||
FOO = 123, | ||
} | ||
} | ||
|
||
namespace foo.bar { | ||
[GenerateInterface] | ||
public partial class Wrapper { | ||
[Const] | ||
public void Foo(SomeType? value = {{enumValue}}); | ||
} | ||
} | ||
""", | ||
$$""" | ||
namespace foo.bar { | ||
public partial class Wrapper : IWrapper; | ||
|
||
#nullable enable | ||
public interface IWrapper { | ||
public void Foo(other.SomeType? value = {{readonlyValue}}); | ||
} | ||
} | ||
|
||
"""); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
using System; | ||
using System.IO; | ||
using System.Linq; | ||
|
||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
|
||
using NUnit.Framework; | ||
|
||
using schema.binary; | ||
using schema.readOnly; | ||
using schema.util.asserts; | ||
|
||
#pragma warning disable CS8604 | ||
|
||
|
||
namespace schema.autoInterface; | ||
|
||
internal static class InterfaceGeneratorTestUtil { | ||
public static void AssertGenerated(string src, params string[] expected) { | ||
var syntaxTree = CSharpSyntaxTree.ParseText(src); | ||
var compilation = BinarySchemaTestUtil.Compilation.Clone() | ||
.AddSyntaxTrees(syntaxTree); | ||
|
||
var semanticModel = compilation.GetSemanticModel(syntaxTree); | ||
|
||
var actual = syntaxTree | ||
.GetRoot() | ||
.DescendantTokens() | ||
.Where(t => t is { | ||
Text: "GenerateInterface", | ||
Parent.Parent: AttributeSyntax | ||
}) | ||
.Select(t => t.Parent?.Parent as AttributeSyntax) | ||
.Select(attributeSyntax => { | ||
var attributeListSyntax | ||
= Asserts.AsA<AttributeListSyntax>( | ||
attributeSyntax.Parent); | ||
var declarationSyntax | ||
= Asserts.AsA<TypeDeclarationSyntax>( | ||
attributeListSyntax.Parent); | ||
var symbol | ||
= semanticModel | ||
.GetDeclaredSymbol(declarationSyntax); | ||
var namedTypeSymbol | ||
= symbol as INamedTypeSymbol; | ||
return (namedTypeSymbol, declarationSyntax); | ||
}) | ||
.Select(symbolAndSyntax | ||
=> new AutoInterfaceTypeGenerator() | ||
.GenerateSourceForNamedType( | ||
symbolAndSyntax.namedTypeSymbol, | ||
semanticModel, | ||
symbolAndSyntax.declarationSyntax) | ||
.ReplaceLineEndings()); | ||
|
||
CollectionAssert.AreEqual(expected, actual); | ||
} | ||
} |
Oops, something went wrong.