mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 00:39:00 +08:00
### 属性参数校验(Attribute Validation)
- AutoUiPageGenerator
- 新增 GF_AutoBehavior_004 诊断:
- 检测 AutoUiPageAttribute 参数无效情况
- 添加测试用例验证错误参数的诊断报告
- AutoRegisterExportedCollectionsGenerator
- 新增 GF_AutoExport_008 诊断:
- 检测 RegisterExportedCollectionAttribute 参数无效情况
- 改进 TryGetRegistrationAttributeArguments 方法:
- 精确报告错误位置
- 更新文档以包含新增诊断规则
### 泛型约束支持(Generic Constraints)
- AutoUiPageGenerator / AutoRegisterModuleGenerator
- 支持以下泛型约束的正确生成:
- class?
- notnull
- unmanaged
- 添加对应测试用例确保生成正确性
### 诊断体系优化(Diagnostics Improvements)
- AutoRegisterModuleGenerator
- 重构 AutoRegisterModuleDiagnostics:
- 优化诊断定义顺序,提高可读性与维护性
208 lines
10 KiB
C#
208 lines
10 KiB
C#
using GFramework.SourceGenerators.Architectures;
|
|
using GFramework.SourceGenerators.Tests.Core;
|
|
|
|
namespace GFramework.SourceGenerators.Tests.Architectures;
|
|
|
|
[TestFixture]
|
|
public class AutoRegisterModuleGeneratorTests
|
|
{
|
|
[Test]
|
|
public async Task Generates_Module_Install_Method_In_Attribute_Order()
|
|
{
|
|
const string source = """
|
|
using System;
|
|
using GFramework.SourceGenerators.Abstractions.Architectures;
|
|
|
|
namespace GFramework.SourceGenerators.Abstractions.Architectures
|
|
{
|
|
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
|
public sealed class AutoRegisterModuleAttribute : Attribute { }
|
|
|
|
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
|
|
public sealed class RegisterModelAttribute : Attribute
|
|
{
|
|
public RegisterModelAttribute(Type modelType) { }
|
|
}
|
|
|
|
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
|
|
public sealed class RegisterSystemAttribute : Attribute
|
|
{
|
|
public RegisterSystemAttribute(Type systemType) { }
|
|
}
|
|
|
|
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
|
|
public sealed class RegisterUtilityAttribute : Attribute
|
|
{
|
|
public RegisterUtilityAttribute(Type utilityType) { }
|
|
}
|
|
}
|
|
|
|
namespace GFramework.Core.Abstractions.Architectures
|
|
{
|
|
public interface IArchitecture
|
|
{
|
|
T RegisterModel<T>(T model) where T : GFramework.Core.Abstractions.Model.IModel;
|
|
T RegisterSystem<T>(T system) where T : GFramework.Core.Abstractions.Systems.ISystem;
|
|
T RegisterUtility<T>(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility;
|
|
}
|
|
}
|
|
|
|
namespace GFramework.Core.Abstractions.Model
|
|
{
|
|
public interface IModel { }
|
|
}
|
|
|
|
namespace GFramework.Core.Abstractions.Systems
|
|
{
|
|
public interface ISystem { }
|
|
}
|
|
|
|
namespace GFramework.Core.Abstractions.Utility
|
|
{
|
|
public interface IUtility { }
|
|
}
|
|
|
|
namespace TestApp
|
|
{
|
|
using GFramework.Core.Abstractions.Model;
|
|
using GFramework.Core.Abstractions.Systems;
|
|
using GFramework.Core.Abstractions.Utility;
|
|
using GFramework.SourceGenerators.Abstractions.Architectures;
|
|
|
|
public sealed class PlayerModel : IModel { }
|
|
public sealed class CombatSystem : ISystem { }
|
|
public sealed class AudioUtility : IUtility { }
|
|
|
|
[AutoRegisterModule]
|
|
[RegisterSystem(typeof(CombatSystem))]
|
|
[RegisterModel(typeof(PlayerModel))]
|
|
[RegisterUtility(typeof(AudioUtility))]
|
|
public partial class GameplayModule
|
|
{
|
|
}
|
|
}
|
|
""";
|
|
|
|
const string expected = """
|
|
// <auto-generated />
|
|
#nullable enable
|
|
|
|
namespace TestApp;
|
|
|
|
partial class GameplayModule
|
|
{
|
|
public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture)
|
|
{
|
|
architecture.RegisterSystem(new global::TestApp.CombatSystem());
|
|
architecture.RegisterModel(new global::TestApp.PlayerModel());
|
|
architecture.RegisterUtility(new global::TestApp.AudioUtility());
|
|
}
|
|
}
|
|
|
|
""";
|
|
|
|
await GeneratorTest<AutoRegisterModuleGenerator>.RunAsync(
|
|
source,
|
|
("TestApp_GameplayModule.AutoRegisterModule.g.cs", expected));
|
|
}
|
|
|
|
[Test]
|
|
public async Task Generates_Type_Constraints_For_NullableReference_NotNull_And_Unmanaged()
|
|
{
|
|
const string source = """
|
|
#nullable enable
|
|
using System;
|
|
using GFramework.SourceGenerators.Abstractions.Architectures;
|
|
|
|
namespace GFramework.SourceGenerators.Abstractions.Architectures
|
|
{
|
|
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
|
public sealed class AutoRegisterModuleAttribute : Attribute { }
|
|
|
|
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
|
|
public sealed class RegisterModelAttribute : Attribute
|
|
{
|
|
public RegisterModelAttribute(Type modelType) { }
|
|
}
|
|
|
|
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
|
|
public sealed class RegisterSystemAttribute : Attribute
|
|
{
|
|
public RegisterSystemAttribute(Type systemType) { }
|
|
}
|
|
|
|
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
|
|
public sealed class RegisterUtilityAttribute : Attribute
|
|
{
|
|
public RegisterUtilityAttribute(Type utilityType) { }
|
|
}
|
|
}
|
|
|
|
namespace GFramework.Core.Abstractions.Architectures
|
|
{
|
|
public interface IArchitecture
|
|
{
|
|
T RegisterModel<T>(T model) where T : GFramework.Core.Abstractions.Model.IModel;
|
|
T RegisterSystem<T>(T system) where T : GFramework.Core.Abstractions.Systems.ISystem;
|
|
T RegisterUtility<T>(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility;
|
|
}
|
|
}
|
|
|
|
namespace GFramework.Core.Abstractions.Model
|
|
{
|
|
public interface IModel { }
|
|
}
|
|
|
|
namespace GFramework.Core.Abstractions.Systems
|
|
{
|
|
public interface ISystem { }
|
|
}
|
|
|
|
namespace GFramework.Core.Abstractions.Utility
|
|
{
|
|
public interface IUtility { }
|
|
}
|
|
|
|
namespace TestApp
|
|
{
|
|
using GFramework.Core.Abstractions.Model;
|
|
using GFramework.SourceGenerators.Abstractions.Architectures;
|
|
|
|
public sealed class PlayerModel : IModel { }
|
|
|
|
[AutoRegisterModule]
|
|
[RegisterModel(typeof(PlayerModel))]
|
|
public partial class GameplayModule<TNullableRef, TNotNull, TUnmanaged>
|
|
where TNullableRef : class?
|
|
where TNotNull : notnull
|
|
where TUnmanaged : unmanaged
|
|
{
|
|
}
|
|
}
|
|
""";
|
|
|
|
const string expected = """
|
|
// <auto-generated />
|
|
#nullable enable
|
|
|
|
namespace TestApp;
|
|
|
|
partial class GameplayModule<TNullableRef, TNotNull, TUnmanaged>
|
|
where TNullableRef : class?
|
|
where TNotNull : notnull
|
|
where TUnmanaged : unmanaged
|
|
{
|
|
public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture)
|
|
{
|
|
architecture.RegisterModel(new global::TestApp.PlayerModel());
|
|
}
|
|
}
|
|
|
|
""";
|
|
|
|
await GeneratorTest<AutoRegisterModuleGenerator>.RunAsync(
|
|
source,
|
|
("TestApp_GameplayModule.AutoRegisterModule.g.cs", expected));
|
|
}
|
|
}
|