解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
大石头 authored at 2018-05-15 21:21:05
4.30 KiB
X
using System;
using System.Linq;
using Microsoft.CodeAnalysis;
using NewLife.SourceGenerator;
using Xunit;

namespace XUnitTest.SourceGenerator;

/// <summary>Json 成员访问生成器测试</summary>
public class JsonSerializableGeneratorTests
{
    #region 测试源码
    private const String Stub = """
namespace NewLife.Reflection
{
    public static class MemberAccessorTable
    {
        public static void Register(Type type, String name, Func<Object, Object?>? getter, Action<Object, Object?>? setter) { }
    }

    public static class Reflect
    {
        public static T? ChangeType<T>(Object? value) => default;
    }
}
""";

    private const String Source = """
[JsonSerializable(typeof(SmokeModel))]
public partial class SmokeContext { }

[JsonSerializable(typeof(DerivedModel))]
public partial class DerivedContext { }

public class SmokeModel
{
    public String Name { get; set; } = "";
    public Int32 Count { get; set; }
    public String? Note { get; set; }
    public Int32? Level { get; set; }
    public String ReadOnly => "x";
    public String InitOnly { get; init; } = "";
    public readonly String Fixed = "";
    public String Field = "";
    public (Int32, String) Pair { get; set; }
    public Int32[]? Items { get; set; }
}

public class BaseModel
{
    public Int32 BaseProp { get; set; }
}

public class DerivedModel : BaseModel
{
    public String DerivedProp { get; set; } = "";
}
""";

    private static readonly String FullSource = "using System;" + Environment.NewLine + "using System.Text.Json.Serialization;" + Environment.NewLine + Stub + Environment.NewLine + Source;
    private static readonly MetadataReference[] ExtraRefs = [];
    #endregion

    #region 测试
    /// <summary>扫描 JsonSerializable 标记,为可静态访问的公开成员生成读写委托</summary>
    [Fact(DisplayName = "扫描标记类型生成成员访问注册")]
    public void GenerateMembers()
    {
        var (_, result) = GeneratorTestHost.RunWithSymbols(new JsonSerializableGenerator(), FullSource, ["NET5_0_OR_GREATER"], ExtraRefs);
        var sources = GeneratorTestHost.GetGeneratedSources(result);

        var text = Assert.Single(sources).Value;
        Assert.Contains("MemberAccessorTable.Register", text);

        // 常规成员
        Assert.Contains("\"Name\"", text);
        Assert.Contains("\"Count\"", text);
        Assert.Contains("\"Note\"", text);
        Assert.Contains("\"Level\"", text);
        Assert.Contains("\"Items\"", text);
        Assert.Contains("\"Field\"", text);

        // 只读属性/只读字段/init-only:有 getter、无 setter
        Assert.Contains("\"ReadOnly\"", text);
        Assert.Contains("\"Fixed\"", text);
        Assert.Contains("\"InitOnly\"", text);
        Assert.DoesNotContain(".ReadOnly = ", text);
        Assert.DoesNotContain(".Fixed = ", text);
        Assert.DoesNotContain(".InitOnly = ", text);

        // setter 经 ChangeType 统一转换(同类型快路径、null 安全)
        Assert.Contains("ChangeType<global::System.Int32>", text);
        Assert.Contains("ChangeType<global::System.Int32?>", text);

        // 元组成员跳过(避免额外类型引用)
        Assert.DoesNotContain("Pair", text);

        // 继承链成员一并生成
        Assert.Contains("\"BaseProp\"", text);
        Assert.Contains("\"DerivedProp\"", text);
    }

    /// <summary>生成产物与用户代码一起编译无错误(含模块初始化器与访问委托)</summary>
    [Fact(DisplayName = "生成产物参与编译无错误")]
    public void GeneratedSourceCompiles()
    {
        var (compilation, _) = GeneratorTestHost.RunWithSymbols(new JsonSerializableGenerator(), FullSource, ["NET5_0_OR_GREATER"], ExtraRefs);
        var errors = compilation.GetDiagnostics().Where(e => e.Severity == DiagnosticSeverity.Error).ToList();

        Assert.True(errors.Count == 0, String.Join(Environment.NewLine, errors.Select(e => e.ToString())));
    }

    /// <summary>低版本目标(无 NET5_0_OR_GREATER 符号)不生成</summary>
    [Fact(DisplayName = "低版本目标不生成")]
    public void SkipBelowNet5()
    {
        var (_, result) = GeneratorTestHost.RunWithSymbols(new JsonSerializableGenerator(), FullSource, [], ExtraRefs);
        var sources = GeneratorTestHost.GetGeneratedSources(result);

        Assert.Empty(sources);
    }
    #endregion
}