Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,52 +17,52 @@
<local:GeneratedSampleOptionTemplateSelector.BoolOptionTemplate>
<DataTemplate x:DataType="metadata:ToolkitSampleBoolOptionMetadataViewModel">
<ToggleSwitch Header="{x:Bind Title, Mode=OneWay}"
IsOn="{x:Bind BoolValue, Mode=TwoWay}" />
IsOn="{x:Bind BoolValue, Mode=TwoWay}" />
</DataTemplate>
</local:GeneratedSampleOptionTemplateSelector.BoolOptionTemplate>
<local:GeneratedSampleOptionTemplateSelector.MultiChoiceOptionTemplate>
<DataTemplate x:DataType="metadata:ToolkitSampleMultiChoiceOptionMetadataViewModel">
<ComboBox Header="{x:Bind Title, Mode=OneWay}"
ItemsSource="{x:Bind Options}"
SelectedIndex="0"
SelectedItem="{x:Bind Value, Mode=TwoWay}" />
ItemsSource="{x:Bind Options}"
SelectedIndex="0"
SelectedItem="{x:Bind Value, Mode=TwoWay}" />
</DataTemplate>
</local:GeneratedSampleOptionTemplateSelector.MultiChoiceOptionTemplate>
<local:GeneratedSampleOptionTemplateSelector.SliderOptionTemplate>
<DataTemplate x:DataType="metadata:ToolkitSampleNumericOptionMetadataViewModel">
<Slider Header="{x:Bind Title, Mode=OneWay}"
Maximum="{x:Bind Max, Mode=OneWay}"
Minimum="{x:Bind Min, Mode=OneWay}"
StepFrequency="{x:Bind Step, Mode=OneWay}"
Value="{x:Bind Initial, Mode=TwoWay}" />
Maximum="{x:Bind Max, Mode=OneWay}"
Minimum="{x:Bind Min, Mode=OneWay}"
StepFrequency="{x:Bind Step, Mode=OneWay}"
Value="{x:Bind Initial, Mode=TwoWay}" />
</DataTemplate>
</local:GeneratedSampleOptionTemplateSelector.SliderOptionTemplate>
<local:GeneratedSampleOptionTemplateSelector.NumberBoxOptionTemplate>
<DataTemplate x:DataType="metadata:ToolkitSampleNumericOptionMetadataViewModel">
<muxc:NumberBox Header="{x:Bind Title, Mode=OneWay}"
Maximum="{x:Bind Max, Mode=OneWay}"
Minimum="{x:Bind Min, Mode=OneWay}"
SmallChange="{x:Bind Step, Mode=OneWay}"
SpinButtonPlacementMode="Compact"
Value="{x:Bind Initial, Mode=TwoWay}" />
Maximum="{x:Bind Max, Mode=OneWay}"
Minimum="{x:Bind Min, Mode=OneWay}"
SmallChange="{x:Bind Step, Mode=OneWay}"
SpinButtonPlacementMode="Compact"
Value="{x:Bind Initial, Mode=TwoWay}" />
</DataTemplate>
</local:GeneratedSampleOptionTemplateSelector.NumberBoxOptionTemplate>
<local:GeneratedSampleOptionTemplateSelector.TextOptionTemplate>
<DataTemplate x:DataType="metadata:ToolkitSampleTextOptionMetadataViewModel">
<TextBox HorizontalAlignment="Stretch"
Header="{x:Bind Title, Mode=OneWay}"
Text="{x:Bind PlaceholderText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Header="{x:Bind Title, Mode=OneWay}"
Text="{x:Bind PlaceholderText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</local:GeneratedSampleOptionTemplateSelector.TextOptionTemplate>
</local:GeneratedSampleOptionTemplateSelector>
</UserControl.Resources>

<ItemsControl ItemTemplateSelector="{StaticResource GeneratedSampleOptionTemplateSelector}"
ItemsSource="{x:Bind SampleOptions, Mode=OneWay}">
ItemsSource="{x:Bind SampleOptions, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"
Spacing="12" />
Spacing="12" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;

namespace CommunityToolkit.Tooling.SampleGen.Tests.Helpers;

internal class InMemoryAdditionalText : AdditionalText
{
private readonly SourceText _content;

public InMemoryAdditionalText(string path, string content)
{
Path = path;
_content = SourceText.From(content, Encoding.UTF8);
}

public override string Path { get; }

public override SourceText GetText(CancellationToken cancellationToken = default) => _content;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// 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 Microsoft.CodeAnalysis;
using System.Collections.Immutable;

namespace CommunityToolkit.Tooling.SampleGen.Tests.Helpers;

public record SourceGeneratorRunResult(Compilation Compilation, ImmutableArray<Diagnostic> Diagnostics);
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// 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 Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Collections.Immutable;

namespace CommunityToolkit.Tooling.SampleGen.Tests.Helpers;

public static partial class TestHelpers
{
internal static IEnumerable<MetadataReference> GetAllReferencedAssemblies()
{
return from assembly in AppDomain.CurrentDomain.GetAssemblies()
where !assembly.IsDynamic
let reference = MetadataReference.CreateFromFile(assembly.Location)
select reference;
}

internal static SyntaxTree ToSyntaxTree(this string source)
{
return CSharpSyntaxTree.ParseText(source,
CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp10));
}

internal static CSharpCompilation CreateCompilation(this SyntaxTree syntaxTree, string assemblyName, IEnumerable<MetadataReference>? references = null)
{
return CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, references ?? GetAllReferencedAssemblies(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
}

internal static CSharpCompilation CreateCompilation(this IEnumerable<SyntaxTree> syntaxTree, string assemblyName, IEnumerable<MetadataReference>? references = null)
{
return CSharpCompilation.Create(assemblyName, syntaxTree, references ?? GetAllReferencedAssemblies(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
}

internal static GeneratorDriver CreateSourceGeneratorDriver(this SyntaxTree syntaxTree, params IIncrementalGenerator[] generators)
{
return CSharpGeneratorDriver.Create(generators).WithUpdatedParseOptions((CSharpParseOptions)syntaxTree.Options);
}

internal static GeneratorDriver CreateSourceGeneratorDriver(this Compilation compilation, params IIncrementalGenerator[] generators)
{
return CSharpGeneratorDriver.Create(generators).WithUpdatedParseOptions((CSharpParseOptions)compilation.SyntaxTrees.First().Options);
}

internal static GeneratorDriver WithMarkdown(this GeneratorDriver driver, params string[] markdownFilesToCreate)
{
foreach (var markdown in markdownFilesToCreate)
{
if (!string.IsNullOrWhiteSpace(markdown))
{
var text = new InMemoryAdditionalText(@"C:\pathtorepo\components\experiment\samples\experiment.Samples\documentation.md", markdown);
driver = driver.AddAdditionalTexts(ImmutableArray.Create<AdditionalText>(text));
}
}

return driver;
}
}
61 changes: 61 additions & 0 deletions CommunityToolkit.Tooling.SampleGen.Tests/Helpers/TestHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Immutable;

namespace CommunityToolkit.Tooling.SampleGen.Tests.Helpers;

public static partial class TestHelpers
{
internal static SourceGeneratorRunResult RunSourceGenerator<TGenerator>(this string source, string assemblyName, string markdown = "") where TGenerator : class, IIncrementalGenerator, new() => RunSourceGenerator<TGenerator>(source.ToSyntaxTree(), assemblyName, markdown);

internal static SourceGeneratorRunResult RunSourceGenerator<TGenerator>(this SyntaxTree syntaxTree, string assemblyName, string markdown = "")
where TGenerator : class, IIncrementalGenerator, new()
{
var compilation = syntaxTree.CreateCompilation(assemblyName); // assembly name should always be supplied in param
return RunSourceGenerator<TGenerator>(compilation, markdown);
}

internal static SourceGeneratorRunResult RunSourceGenerator<TGenerator>(this Compilation compilation, string markdown = "")
where TGenerator : class, IIncrementalGenerator, new()
{
// Create a driver for the source generator
var driver = compilation
.CreateSourceGeneratorDriver(new TGenerator())
.WithMarkdown(markdown);

// Update the original compilation using the source generator
_ = driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation generatorCompilation, out ImmutableArray<Diagnostic> postGeneratorCompilationDiagnostics);

return new(generatorCompilation, postGeneratorCompilationDiagnostics);
}

internal static void AssertDiagnosticsAre(this IEnumerable<Diagnostic> diagnostics, params DiagnosticDescriptor[] expectedDiagnosticDescriptors)
{
var expectedIds = expectedDiagnosticDescriptors.Select(x => x.Id).ToHashSet();
var resultingIds = diagnostics.Select(diagnostic => diagnostic.Id).ToHashSet();

Assert.IsTrue(resultingIds.SetEquals(expectedIds), $"Expected [{string.Join(", ", expectedIds)}] diagnostic Ids. Got [{string.Join(", ", resultingIds)}]");
}

internal static void AssertNoCompilationErrors(this Compilation outputCompilation)
{
var generatedCompilationDiagnostics = outputCompilation.GetDiagnostics();
Assert.IsTrue(generatedCompilationDiagnostics.All(x => x.Severity != DiagnosticSeverity.Error), $"Expected no generated compilation errors. Got: \n{string.Join("\n", generatedCompilationDiagnostics.Where(x => x.Severity == DiagnosticSeverity.Error).Select(x => $"[{x.Id}: {x.GetMessage()}]"))}");
}

internal static string GetFileContentsByName(this Compilation compilation, string filename)
{
var generatedTree = compilation.SyntaxTrees.SingleOrDefault(tree => Path.GetFileName(tree.FilePath) == filename);
Assert.IsNotNull(generatedTree, $"No file named {filename} was generated");

return generatedTree.ToString();
}

internal static void AssertSourceGenerated(this Compilation compilation, string filename, string expectedContents)
{
}

internal static void AssertDiagnosticsAre(this SourceGeneratorRunResult result, params DiagnosticDescriptor[] expectedDiagnosticDescriptors) => AssertDiagnosticsAre(result.Diagnostics, expectedDiagnosticDescriptors);

internal static void AssertNoCompilationErrors(this SourceGeneratorRunResult result) => AssertNoCompilationErrors(result.Compilation);
}
Loading