// 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 System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace CommunityToolkit.Mvvm.SourceGenerators.UnitTests;
[TestClass]
public class Test_SourceGeneratorsCodegen
{
[TestMethod]
public void ObservablePropertyWithPartialMethodWithPreviousValuesNotUsed_DoesNotGenerateFieldReadAndMarksOldValueAsNullable()
{
string source = """
using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
#nullable enable
namespace MyApp;
partial class MyViewModel : ObservableObject
{
[ObservableProperty]
private string name = null!;
}
""";
string result = """
//
#pragma warning disable
#nullable enable
namespace MyApp
{
partial class MyViewModel
{
///
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public string Name
{
get => name;
set
{
if (!global::System.Collections.Generic.EqualityComparer.Default.Equals(name, value))
{
OnNameChanging(value);
OnNameChanging(default, value);
OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Name);
name = value;
OnNameChanged(value);
OnNameChanged(default, value);
OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Name);
}
}
}
/// Executes the logic for when is changing.
/// The new property value being set.
/// This method is invoked right before the value of is changed.
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
partial void OnNameChanging(string value);
/// Executes the logic for when is changing.
/// The previous property value that is being replaced.
/// The new property value being set.
/// This method is invoked right before the value of is changed.
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
partial void OnNameChanging(string? oldValue, string newValue);
/// Executes the logic for when just changed.
/// The new property value that was set.
/// This method is invoked right after the value of is changed.
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
partial void OnNameChanged(string value);
/// Executes the logic for when just changed.
/// The previous property value that was replaced.
/// The new property value that was set.
/// This method is invoked right after the value of is changed.
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
partial void OnNameChanged(string? oldValue, string newValue);
}
}
""";
VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, ("MyApp.MyViewModel.g.cs", result));
}
// See https://github.com/CommunityToolkit/dotnet/issues/601
[TestMethod]
public void ObservablePropertyWithForwardedAttributesWithNumberLiterals_PreservesType()
{
string source = """
using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
#nullable enable
namespace MyApp;
partial class MyViewModel : ObservableObject
{
const double MyDouble = 3.14;
const float MyFloat = 3.14f;
[ObservableProperty]
[property: DefaultValue(0.0)]
[property: DefaultValue(1.24)]
[property: DefaultValue(0.0f)]
[property: DefaultValue(0.0f)]
[property: DefaultValue(MyDouble)]
[property: DefaultValue(MyFloat)]
private object? a;
}
public class DefaultValueAttribute : Attribute
{
public DefaultValueAttribute(object value)
{
}
}
""";
string result = """
//
#pragma warning disable
#nullable enable
namespace MyApp
{
partial class MyViewModel
{
///
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::MyApp.DefaultValueAttribute(0D)]
[global::MyApp.DefaultValueAttribute(1.24D)]
[global::MyApp.DefaultValueAttribute(0F)]
[global::MyApp.DefaultValueAttribute(0F)]
[global::MyApp.DefaultValueAttribute(3.14D)]
[global::MyApp.DefaultValueAttribute(3.14F)]
public object? A
{
get => a;
set
{
if (!global::System.Collections.Generic.EqualityComparer