Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sample options and viewable source #29

Merged
merged 29 commits into from
Mar 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0061a80
Enable including C# and XAML source files as bundled content
Arlodotexe Jan 21, 2022
2a237ea
Merge branch 'main' into feature/displaying-sample-code
Arlodotexe Jan 21, 2022
c20248a
Added ToolkitSampleRenderer. Implemented ToolkitSampleOptionsPane. Ad…
Arlodotexe Jan 21, 2022
128f9f7
Moved ToolkitSampleMetadataGenerator to new folder/namespace
Arlodotexe Jan 21, 2022
b8d8806
Extracted generic source generator helpers as extension methods
Arlodotexe Jan 21, 2022
28774dd
Fixed an issue where output was generated when no attributes were found
Arlodotexe Jan 25, 2022
10c5e86
Added CrawlBy helper
Arlodotexe Jan 25, 2022
90a2049
Added XamlNamedPropertyRelayGenerator
Arlodotexe Jan 25, 2022
239caaa
Include all x-plat libraries in source generation
Arlodotexe Jan 25, 2022
7c7fbe2
Cleaned up manually created XamlNamedPropertyRelay
Arlodotexe Jan 25, 2022
c2324d3
Strip out toolkit attributes from displayed code, enable text selection
Arlodotexe Jan 25, 2022
ccbca53
Fixed options pane taking up space when there's no content
Arlodotexe Jan 26, 2022
6b182d7
Split generators into 2 projects. Created generated pane options. Add…
Arlodotexe Jan 31, 2022
26c8ab6
Merged
Arlodotexe Feb 4, 2022
2238e52
Fixed missing WinAppSDK sample head in CanvasLayout project
Arlodotexe Feb 4, 2022
6133bf0
Added title property to generated sample pane option
Arlodotexe Feb 4, 2022
e7d1506
Added generated multi-choice option for sample options pane
Arlodotexe Feb 7, 2022
f68600f
Added diagnostic descriptions for duplicate property names + tests
Arlodotexe Feb 7, 2022
40d4af3
Added diagnostics for generated options that contain conflicting prop…
Arlodotexe Feb 7, 2022
72e2db3
Added multi-choice extra title diagnostic error + tests
Arlodotexe Feb 8, 2022
e4be348
Cleanup, added remaining unit tests
Arlodotexe Feb 8, 2022
9ec8cf4
Moved unused sample options pane to second sample
Arlodotexe Feb 8, 2022
2779af4
Fixed namespaces
Arlodotexe Feb 8, 2022
3cfa615
Cleaning up comments
Arlodotexe Feb 8, 2022
217787a
Added generator summary
Arlodotexe Feb 8, 2022
53e5fe5
Improved and expanded comments, minor cleanup.
Arlodotexe Feb 8, 2022
85d648d
Merge
Arlodotexe Feb 17, 2022
16e0e7c
Added missing comment
Arlodotexe Feb 17, 2022
c71694d
Removed extraneous extensions helpers
Arlodotexe Feb 18, 2022
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
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.7" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.7" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\CommunityToolkit.Labs.Core.SourceGenerators\CommunityToolkit.Labs.Core.SourceGenerators.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,356 @@
using CommunityToolkit.Labs.Core.SourceGenerators.Attributes;
using CommunityToolkit.Labs.Core.SourceGenerators.Diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;

namespace CommunityToolkit.Labs.Core.SourceGenerators.Tests
{
[TestClass]
public class ToolkitSampleMetadataTests
{
[TestMethod]
public void PaneOptionOnNonSample()
{
string source = @"
using System.ComponentModel;
using CommunityToolkit.Labs.Core.SourceGenerators.Attributes;

namespace MyApp
{
[ToolkitSampleBoolOption(""BindToMe"", ""Toggle visibility"", false)]
public partial class Sample : Windows.UI.Xaml.Controls.UserControl
{
}
}

namespace Windows.UI.Xaml.Controls
{
public class UserControl { }
}";

VerifyGeneratedDiagnostics<ToolkitSampleMetadataGenerator>(source, DiagnosticDescriptors.SamplePaneOptionAttributeOnNonSample.Id);
}

[DataRow("", DisplayName = "Empty string"), DataRow(" ", DisplayName = "Only whitespace"), DataRow("Test ", DisplayName = "Text with whitespace")]
[DataRow("_", DisplayName = "Underscore"), DataRow("$", DisplayName = "Dollar sign"), DataRow("%", DisplayName = "Percent symbol")]
[DataRow("class", DisplayName = "Reserved keyword 'class'"), DataRow("string", DisplayName = "Reserved keyword 'string'"), DataRow("sealed", DisplayName = "Reserved keyword 'sealed'"), DataRow("ref", DisplayName = "Reserved keyword 'ref'")]
[TestMethod]
public void PaneOptionWithBadName(string name)
{
var source = $@"
using System.ComponentModel;
using CommunityToolkit.Labs.Core.SourceGenerators;
using CommunityToolkit.Labs.Core.SourceGenerators.Attributes;

namespace MyApp
{{
[ToolkitSample(id: nameof(Sample), ""Test Sample"", ToolkitSampleCategory.Controls, ToolkitSampleSubcategory.Layout, description: """")]
[ToolkitSampleBoolOption(""{name}"", ""Toggle visibility"", false)]
public partial class Sample : Windows.UI.Xaml.Controls.UserControl
{{
}}
}}

namespace Windows.UI.Xaml.Controls
{{
public class UserControl {{ }}
}}";

VerifyGeneratedDiagnostics<ToolkitSampleMetadataGenerator>(source, DiagnosticDescriptors.SamplePaneOptionWithBadName.Id);
}

[TestMethod]
public void PaneOptionWithConflictingPropertyName()
{
var source = $@"
using System.ComponentModel;
using CommunityToolkit.Labs.Core.SourceGenerators;
using CommunityToolkit.Labs.Core.SourceGenerators.Attributes;

namespace MyApp
{{
[ToolkitSampleBoolOption(""IsVisible"", ""Toggle x"", false)]
[ToolkitSample(id: nameof(Sample), ""Test Sample"", ToolkitSampleCategory.Controls, ToolkitSampleSubcategory.Layout, description: """")]
public partial class Sample : Windows.UI.Xaml.Controls.UserControl
{{
public string IsVisible {{ get; set; }}
}}
}}

namespace Windows.UI.Xaml.Controls
{{
public class UserControl {{ }}
}}";

VerifyGeneratedDiagnostics<ToolkitSampleMetadataGenerator>(source, DiagnosticDescriptors.SamplePaneOptionWithConflictingName.Id);
}

[TestMethod]
public void PaneOptionWithConflictingInheritedPropertyName()
{
var source = $@"
using System.ComponentModel;
using CommunityToolkit.Labs.Core.SourceGenerators;
using CommunityToolkit.Labs.Core.SourceGenerators.Attributes;

namespace MyApp
{{
[ToolkitSampleBoolOption(""IsVisible"", ""Toggle x"", false)]
[ToolkitSample(id: nameof(Sample), ""Test Sample"", ToolkitSampleCategory.Controls, ToolkitSampleSubcategory.Layout, description: """")]
public partial class Sample : Base
{{
}}

public class Base : Windows.UI.Xaml.Controls.UserControl
{{
public string IsVisible {{ get; set; }}
}}
}}

namespace Windows.UI.Xaml.Controls
{{
public class UserControl {{ }}
}}";

VerifyGeneratedDiagnostics<ToolkitSampleMetadataGenerator>(source, DiagnosticDescriptors.SamplePaneOptionWithConflictingName.Id);
}

[TestMethod]
public void PaneOptionWithDuplicateName()
{
var source = $@"
using System.ComponentModel;
using CommunityToolkit.Labs.Core.SourceGenerators;
using CommunityToolkit.Labs.Core.SourceGenerators.Attributes;

namespace MyApp
{{
[ToolkitSampleBoolOption(""test"", ""Toggle x"", false)]
[ToolkitSampleBoolOption(""test"", ""Toggle y"", false)]

[ToolkitSample(id: nameof(Sample), ""Test Sample"", ToolkitSampleCategory.Controls, ToolkitSampleSubcategory.Layout, description: """")]
public partial class Sample : Windows.UI.Xaml.Controls.UserControl
{{
}}
}}

namespace Windows.UI.Xaml.Controls
{{
public class UserControl {{ }}
}}";

VerifyGeneratedDiagnostics<ToolkitSampleMetadataGenerator>(source, DiagnosticDescriptors.SamplePaneOptionWithDuplicateName.Id);
}

[TestMethod]
public void PaneOptionWithDuplicateName_AllowedForMultiChoice()
{
var source = $@"
using System.ComponentModel;
using CommunityToolkit.Labs.Core.SourceGenerators;
using CommunityToolkit.Labs.Core.SourceGenerators.Attributes;

namespace MyApp
{{
[ToolkitSampleMultiChoiceOption(""TextFontFamily"", label: ""Segoe UI"", value: ""Segoe UI"", title: ""Font"")]
[ToolkitSampleMultiChoiceOption(""TextFontFamily"", label: ""Arial"", value: ""Arial"")]

[ToolkitSampleBoolOption(""test"", ""Toggle y"", false)]

[ToolkitSample(id: nameof(Sample), ""Test Sample"", ToolkitSampleCategory.Controls, ToolkitSampleSubcategory.Layout, description: """")]
public partial class Sample : Windows.UI.Xaml.Controls.UserControl
{{
}}
}}

namespace Windows.UI.Xaml.Controls
{{
public class UserControl {{ }}
}}";

VerifyGeneratedDiagnostics<ToolkitSampleMetadataGenerator>(source);
}

[TestMethod]
public void PaneOptionWithDuplicateName_AllowedBetweenSamples()
{
var source = $@"
using System.ComponentModel;
using CommunityToolkit.Labs.Core.SourceGenerators;
using CommunityToolkit.Labs.Core.SourceGenerators.Attributes;

namespace MyApp
{{
[ToolkitSampleBoolOption(""test"", ""Toggle y"", false)]

[ToolkitSample(id: nameof(Sample), ""Test Sample"", ToolkitSampleCategory.Controls, ToolkitSampleSubcategory.Layout, description: """")]
public partial class Sample : Windows.UI.Xaml.Controls.UserControl
{{
}}

[ToolkitSampleBoolOption(""test"", ""Toggle y"", false)]

[ToolkitSample(id: nameof(Sample2), ""Test Sample"", ToolkitSampleCategory.Controls, ToolkitSampleSubcategory.Layout, description: """")]
public partial class Sample2 : Windows.UI.Xaml.Controls.UserControl
{{
}}
}}

namespace Windows.UI.Xaml.Controls
{{
public class UserControl {{ }}
}}";

VerifyGeneratedDiagnostics<ToolkitSampleMetadataGenerator>(source);
}

[TestMethod]
public void PaneMultipleChoiceOptionWithMultipleTitles()
{
var source = $@"
using System.ComponentModel;
using CommunityToolkit.Labs.Core.SourceGenerators;
using CommunityToolkit.Labs.Core.SourceGenerators.Attributes;

namespace MyApp
{{
[ToolkitSampleMultiChoiceOption(""TextFontFamily"", label: ""Segoe UI"", value: ""Segoe UI"", title: ""Font"")]
[ToolkitSampleMultiChoiceOption(""TextFontFamily"", label: ""Arial"", value: ""Arial"", title: ""Other font"")]

[ToolkitSample(id: nameof(Sample), ""Test Sample"", ToolkitSampleCategory.Controls, ToolkitSampleSubcategory.Layout, description: """")]
public partial class Sample : Windows.UI.Xaml.Controls.UserControl
{{
}}
}}

namespace Windows.UI.Xaml.Controls
{{
public class UserControl {{ }}
}}";

VerifyGeneratedDiagnostics<ToolkitSampleMetadataGenerator>(source, DiagnosticDescriptors.SamplePaneMultiChoiceOptionWithMultipleTitles.Id);
}

[TestMethod]
public void SampleGeneratedOptionAttributeOnUnsupportedType()
{
var source = $@"
using System.ComponentModel;
using CommunityToolkit.Labs.Core.SourceGenerators;
using CommunityToolkit.Labs.Core.SourceGenerators.Attributes;

namespace MyApp
{{
[ToolkitSampleMultiChoiceOption(""TextFontFamily"", label: ""Segoe UI"", value: ""Segoe UI"", title: ""Font"")]
[ToolkitSampleMultiChoiceOption(""TextFontFamily"", label: ""Arial"", value: ""Arial"")]
[ToolkitSampleBoolOption(""Test"", ""Toggle visibility"", false)]
public partial class Sample
{{
}}
}}";

VerifyGeneratedDiagnostics<ToolkitSampleMetadataGenerator>(source, DiagnosticDescriptors.SampleGeneratedOptionAttributeOnUnsupportedType.Id, DiagnosticDescriptors.SamplePaneOptionAttributeOnNonSample.Id);
}

[TestMethod]
public void SampleAttributeOnUnsupportedType()
{
var source = $@"
using System.ComponentModel;
using CommunityToolkit.Labs.Core.SourceGenerators;
using CommunityToolkit.Labs.Core.SourceGenerators.Attributes;

namespace MyApp
{{
[ToolkitSample(id: nameof(Sample), ""Test Sample"", ToolkitSampleCategory.Controls, ToolkitSampleSubcategory.Layout, description: """")]
public partial class Sample
{{
}}
}}";

VerifyGeneratedDiagnostics<ToolkitSampleMetadataGenerator>(source, DiagnosticDescriptors.SampleAttributeOnUnsupportedType.Id);
}

[TestMethod]
public void SampleOptionPaneAttributeOnUnsupportedType()
{
var source = $@"
using System.ComponentModel;
using CommunityToolkit.Labs.Core.SourceGenerators;
using CommunityToolkit.Labs.Core.SourceGenerators.Attributes;

namespace MyApp
{{
[ToolkitSampleOptionsPane(sampleId: nameof(Sample))]
public partial class SampleOptionsPane
{{
}}

[ToolkitSample(id: nameof(Sample), ""Test Sample"", ToolkitSampleCategory.Controls, ToolkitSampleSubcategory.Layout, description: """")]
public partial class Sample : Windows.UI.Xaml.Controls.UserControl
{{
}}
}}

namespace Windows.UI.Xaml.Controls
{{
public class UserControl {{ }}
}}";

VerifyGeneratedDiagnostics<ToolkitSampleMetadataGenerator>(source, DiagnosticDescriptors.SampleOptionPaneAttributeOnUnsupportedType.Id);
}

/// <summary>
/// Verifies the output of a source generator.
/// </summary>
/// <typeparam name="TGenerator">The generator type to use.</typeparam>
/// <param name="source">The input source to process.</param>
/// <param name="diagnosticsIds">The diagnostic ids to expect for the input source code.</param>
private static void VerifyGeneratedDiagnostics<TGenerator>(string source, params string[] diagnosticsIds)
where TGenerator : class, IIncrementalGenerator, new()
{
VerifyGeneratedDiagnostics<TGenerator>(CSharpSyntaxTree.ParseText(source), diagnosticsIds);
}

/// <summary>
/// Verifies the output of a source generator.
/// </summary>
/// <typeparam name="TGenerator">The generator type to use.</typeparam>
/// <param name="syntaxTree">The input source tree to process.</param>
/// <param name="diagnosticsIds">The diagnostic ids to expect for the input source code.</param>
private static void VerifyGeneratedDiagnostics<TGenerator>(SyntaxTree syntaxTree, params string[] diagnosticsIds)
where TGenerator : class, IIncrementalGenerator, new()
{
var sampleAttributeType = typeof(ToolkitSampleAttribute);

var references =
from assembly in AppDomain.CurrentDomain.GetAssemblies()
where !assembly.IsDynamic
let reference = MetadataReference.CreateFromFile(assembly.Location)
select reference;

var compilation = CSharpCompilation.Create(
"original",
new[] { syntaxTree },
references,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

IIncrementalGenerator generator = new TGenerator();

GeneratorDriver driver = CSharpGeneratorDriver.Create(generator).WithUpdatedParseOptions((CSharpParseOptions)syntaxTree.Options);

_ = driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray<Diagnostic> diagnostics);

HashSet<string> resultingIds = diagnostics.Select(diagnostic => diagnostic.Id).ToHashSet();

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

GC.KeepAlive(sampleAttributeType);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>nullable</WarningsAsErrors>
<LangVersion>10.0</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
</ItemGroup>
</Project>
Loading