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
@@ -0,0 +1,95 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using System.IO;
using System.Collections.Generic;
using Xunit;

namespace CommunityToolkit.Maui.SourceGenerators.Internal.UnitTests.AttachedBindablePropertySourceGeneratorTests;

public class BaseAttachedBindablePropertyAttributeSourceGeneratorTest : CommunityToolkit.Maui.SourceGenerators.Internal.UnitTests.BaseTest
{
protected const string defaultTestClassName = "TestView";
protected const string defaultTestNamespace = "TestNamespace";

protected const string expectedAttribute =
/* language=C#-test */
//lang=csharp
$$"""
// <auto-generated>
// See: CommunityToolkit.Maui.SourceGenerators.Internal.AttachedBindablePropertySourceGenerator

#pragma warning disable
#nullable enable
namespace CommunityToolkit.Maui;

[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
[global::System.Diagnostics.CodeAnalysis.Experimental("{{AttachedBindablePropertySourceGenerator.BindablePropertyAttributeExperimentalDiagnosticId}}")]
sealed partial class AttachedBindablePropertyAttribute : global::System.Attribute
{
public string? PropertyName { get; }
public global::System.Type? DeclaringType { get; set; }
public global::Microsoft.Maui.Controls.BindingMode DefaultBindingMode { get; set; }
public string ValidateValueMethodName { get; set; } = string.Empty;
public string PropertyChangedMethodName { get; set; } = string.Empty;
public string PropertyChangingMethodName { get; set; } = string.Empty;
public string CoerceValueMethodName { get; set; } = string.Empty;
public string DefaultValueCreatorMethodName { get; set; } = string.Empty;
}
""";

protected static async Task VerifyAttachedSourceGeneratorAsync(string source, string expectedGenerated)
{
const string sourceGeneratorNamespace = "CommunityToolkit.Maui.SourceGenerators.Internal";
const string attachedBindablePropertyAttributeGeneratedFileName = "AttachedBindablePropertyAttribute.g.cs";
var attachedSourceGeneratorFullName = typeof(AttachedBindablePropertySourceGenerator).FullName ?? throw new InvalidOperationException("Source Generator Type Path cannot be null");

var test = new AttachedBindablePropertyTest
{
#if NET10_0
ReferenceAssemblies = Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.Net.Net100,
#else
#error ReferenceAssemblies must be updated to current version of .NET
#endif
TestState =
{
Sources = { source },

AdditionalReferences =
{
MetadataReference.CreateFromFile(typeof(Microsoft.Maui.Controls.BindableObject).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Microsoft.Maui.Controls.BindableProperty).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Microsoft.Maui.Controls.BindingMode).Assembly.Location)
}
}
};

var expectedAttributeText = Microsoft.CodeAnalysis.Text.SourceText.From(expectedAttribute, System.Text.Encoding.UTF8);
// Use the same prefix the test harness uses so the expected generated file path matches actual
var attributeFilePath = Path.Combine(sourceGeneratorNamespace, attachedSourceGeneratorFullName, attachedBindablePropertyAttributeGeneratedFileName);
test.TestState.GeneratedSources.Add((attributeFilePath, expectedAttributeText));

if (!string.IsNullOrEmpty(expectedGenerated))
{
var expectedGeneratedText = Microsoft.CodeAnalysis.Text.SourceText.From(expectedGenerated, System.Text.Encoding.UTF8);
var generatedFilePath = Path.Combine(sourceGeneratorNamespace, attachedSourceGeneratorFullName, $"{defaultTestClassName}.g.cs");
test.TestState.GeneratedSources.Add((generatedFilePath, expectedGeneratedText));
}

await test.RunAsync(TestContext.Current.CancellationToken);
}

sealed class AttachedBindablePropertyTest : CSharpSourceGeneratorTest<AttachedBindablePropertySourceGenerator, DefaultVerifier>
{
protected override CompilationOptions CreateCompilationOptions()
{
var compilationOptions = base.CreateCompilationOptions();

return compilationOptions.WithSpecificDiagnosticOptions(new Dictionary<string, ReportDiagnostic>
{
{ AttachedBindablePropertySourceGenerator.BindablePropertyAttributeExperimentalDiagnosticId, ReportDiagnostic.Warn }
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
using System.Threading.Tasks;
using Xunit;

namespace CommunityToolkit.Maui.SourceGenerators.Internal.UnitTests.AttachedBindablePropertySourceGeneratorTests;

public class CommonUsageTests : BaseAttachedBindablePropertyAttributeSourceGeneratorTest
{
[Fact]
public async Task GenerateAttachedBindableProperty_SimpleExample_GeneratesCorrectCode()
{
const string source =
/* language=C#-test */
//lang=csharp
$$"""
using CommunityToolkit.Maui;
using Microsoft.Maui.Controls;

namespace {{defaultTestNamespace}};

public partial class {{defaultTestClassName}} : View
{
[AttachedBindableProperty]
public partial string Text { get; set; }
}
""";

const string expectedGenerated =
/* language=C#-test */
//lang=csharp
$$"""
// <auto-generated>
// See: CommunityToolkit.Maui.SourceGenerators.Internal.AttachedBindablePropertySourceGenerator
#pragma warning disable
#nullable enable
using global::Microsoft.Maui.Controls;

namespace {{defaultTestNamespace}};
public partial class {{defaultTestClassName}}
{
/// <summary>
/// Backing BindableProperty for the <see cref = "Text"/> property.
/// </summary>
public static readonly global::Microsoft.Maui.Controls.BindableProperty TextProperty = global::Microsoft.Maui.Controls.BindableProperty.CreateAttached("Text", typeof(string), typeof({{defaultTestNamespace}}.{{defaultTestClassName}}), null, Microsoft.Maui.Controls.BindingMode.OneWay, null, null, null, null, null);
public partial string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); }

public static string GetText(BindableObject view) => (string)view.GetValue(TextProperty);
public static void SetText(BindableObject view, string value) => view.SetValue(TextProperty, value);
}
""";

await VerifyAttachedSourceGeneratorAsync(source, expectedGenerated);
}

[Fact]
public async Task GenerateAttachedBindableProperty_WithNewKeyword_GeneratesCorrectCode()
{
const string source =
/* language=C#-test */
//lang=csharp
$$"""
using CommunityToolkit.Maui;
using Microsoft.Maui.Controls;

namespace {{defaultTestNamespace}};

public partial class {{defaultTestClassName}} : View
{
[AttachedBindableProperty]
public new partial string Text { get; set; }
}
""";

const string expectedGenerated =
/* language=C#-test */
//lang=csharp
$$"""
// <auto-generated>
// See: CommunityToolkit.Maui.SourceGenerators.Internal.AttachedBindablePropertySourceGenerator
#pragma warning disable
#nullable enable
using global::Microsoft.Maui.Controls;

namespace {{defaultTestNamespace}};
public partial class {{defaultTestClassName}}
{
/// <summary>
/// Backing BindableProperty for the <see cref = "Text"/> property.
/// </summary>
public new static readonly global::Microsoft.Maui.Controls.BindableProperty TextProperty = global::Microsoft.Maui.Controls.BindableProperty.CreateAttached("Text", typeof(string), typeof({{defaultTestNamespace}}.{{defaultTestClassName}}), null, Microsoft.Maui.Controls.BindingMode.OneWay, null, null, null, null, null);
public new partial string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); }

public static string GetText(BindableObject view) => (string)view.GetValue(TextProperty);
public static void SetText(BindableObject view, string value) => view.SetValue(TextProperty, value);
}
""";

await VerifyAttachedSourceGeneratorAsync(source, expectedGenerated);
}

[Fact]
public async Task GenerateAttachedBindableProperty_NullableReferenceType_GeneratesCorrectCode()
{
const string source =
/* language=C#-test */
//lang=csharp
$$"""
using CommunityToolkit.Maui;
using Microsoft.Maui.Controls;

namespace {{defaultTestNamespace}};

public partial class {{defaultTestClassName}} : View
{
[AttachedBindableProperty]
public partial string? Text { get; set; }
}
""";

const string expectedGenerated =
/* language=C#-test */
//lang=csharp
$$"""
// <auto-generated>
// See: CommunityToolkit.Maui.SourceGenerators.Internal.AttachedBindablePropertySourceGenerator
#pragma warning disable
#nullable enable
using global::Microsoft.Maui.Controls;

namespace {{defaultTestNamespace}};
public partial class {{defaultTestClassName}}
{
/// <summary>
/// Backing BindableProperty for the <see cref = "Text"/> property.
/// </summary>
public static readonly global::Microsoft.Maui.Controls.BindableProperty TextProperty = global::Microsoft.Maui.Controls.BindableProperty.CreateAttached("Text", typeof(string), typeof({{defaultTestNamespace}}.{{defaultTestClassName}}), null, Microsoft.Maui.Controls.BindingMode.OneWay, null, null, null, null, null);
public partial string? Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); }

public static string? GetText(BindableObject view) => (string)view.GetValue(TextProperty);
public static void SetText(BindableObject view, string? value) => view.SetValue(TextProperty, value);
}
""";

await VerifyAttachedSourceGeneratorAsync(source, expectedGenerated);
}

[Fact]
public async Task GenerateAttachedBindableProperty_MultipleProperties_GeneratesCorrectCode()
{
const string source =
/* language=C#-test */
//lang=csharp
$$"""
using CommunityToolkit.Maui;
using Microsoft.Maui.Controls;

namespace {{defaultTestNamespace}};

public partial class {{defaultTestClassName}} : View
{
[AttachedBindableProperty]
public partial string Text { get; set; }

[AttachedBindableProperty]
public partial int Number { get; set; }
}
""";

const string expectedGenerated =
/* language=C#-test */
//lang=csharp
$$"""
// <auto-generated>
// See: CommunityToolkit.Maui.SourceGenerators.Internal.AttachedBindablePropertySourceGenerator
#pragma warning disable
#nullable enable
using global::Microsoft.Maui.Controls;

namespace {{defaultTestNamespace}};
public partial class {{defaultTestClassName}}
{
/// <summary>
/// Backing BindableProperty for the <see cref = "Text"/> property.
/// </summary>
public static readonly global::Microsoft.Maui.Controls.BindableProperty TextProperty = global::Microsoft.Maui.Controls.BindableProperty.CreateAttached("Text", typeof(string), typeof({{defaultTestNamespace}}.{{defaultTestClassName}}), null, Microsoft.Maui.Controls.BindingMode.OneWay, null, null, null, null, null);
public partial string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); }

public static string GetText(BindableObject view) => (string)view.GetValue(TextProperty);
public static void SetText(BindableObject view, string value) => view.SetValue(TextProperty, value);
/// <summary>
/// Backing BindableProperty for the <see cref = "Number"/> property.
/// </summary>
public static readonly global::Microsoft.Maui.Controls.BindableProperty NumberProperty = global::Microsoft.Maui.Controls.BindableProperty.CreateAttached("Number", typeof(int), typeof({{defaultTestNamespace}}.{{defaultTestClassName}}), null, Microsoft.Maui.Controls.BindingMode.OneWay, null, null, null, null, null);
public partial int Number { get => (int)GetValue(NumberProperty); set => SetValue(NumberProperty, value); }

public static int GetNumber(BindableObject view) => (int)view.GetValue(NumberProperty);
public static void SetNumber(BindableObject view, int value) => view.SetValue(NumberProperty, value);
}
""";

await VerifyAttachedSourceGeneratorAsync(source, expectedGenerated);
}
}
Loading
Loading