GeWuYou 80acf84e95 feat(godot): 添加AutoScene和AutoRegisterExportedCollections源代码生成器
- 实现AutoSceneGenerator为标记了[AutoScene]特性的Godot节点生成场景行为样板代码
- 实现AutoRegisterExportedCollectionsGenerator为导出集合生成批量注册样板方法
- 添加AutoBehaviorDiagnostics和AutoRegisterExportedCollectionsDiagnostics诊断描述符
- 创建AnalyzerReleases.Unshipped.md文件跟踪新的分析器规则
- 添加完整的单元测试覆盖两个生成器的功能和错误情况
- 更新.gitignore文件排除dotnet-home和脚本缓存目录
2026-04-13 10:51:40 +08:00

134 lines
5.4 KiB
C#

using GFramework.Godot.SourceGenerators.Behavior;
using GFramework.Godot.SourceGenerators.Tests.Core;
namespace GFramework.Godot.SourceGenerators.Tests.Behavior;
[TestFixture]
public class AutoSceneGeneratorTests
{
[Test]
public async Task Generates_Scene_Behavior_Boilerplate()
{
const string source = """
using System;
using GFramework.Godot.SourceGenerators.Abstractions;
using Godot;
namespace GFramework.Godot.SourceGenerators.Abstractions
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class AutoSceneAttribute : Attribute
{
public AutoSceneAttribute(string key) { }
}
}
namespace Godot
{
public class Node { }
public class Node2D : Node { }
}
namespace GFramework.Game.Abstractions.Scene
{
public interface ISceneBehavior { }
}
namespace GFramework.Godot.Scene
{
using GFramework.Game.Abstractions.Scene;
using Godot;
public static class SceneBehaviorFactory
{
public static ISceneBehavior Create<T>(T owner, string key)
where T : Node
{
return null!;
}
}
}
namespace TestApp
{
[AutoScene("Gameplay")]
public partial class GameplayRoot : Node2D
{
}
}
""";
const string expected = """
// <auto-generated />
#nullable enable
namespace TestApp;
partial class GameplayRoot
{
private global::GFramework.Game.Abstractions.Scene.ISceneBehavior? __autoSceneBehavior_Generated;
public static string SceneKeyStr => "Gameplay";
public global::GFramework.Game.Abstractions.Scene.ISceneBehavior GetScene()
{
return __autoSceneBehavior_Generated ??= global::GFramework.Godot.Scene.SceneBehaviorFactory.Create(this, SceneKeyStr);
}
}
""";
await GeneratorTest<AutoSceneGenerator>.RunAsync(
source,
("TestApp_GameplayRoot.AutoScene.g.cs", expected));
}
[Test]
public async Task Reports_Diagnostic_When_AutoScene_Arguments_Are_Invalid()
{
const string source = """
using System;
using GFramework.Godot.SourceGenerators.Abstractions;
using Godot;
namespace GFramework.Godot.SourceGenerators.Abstractions
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class AutoSceneAttribute : Attribute
{
public AutoSceneAttribute() { }
}
}
namespace Godot
{
public class Node { }
public class Node2D : Node { }
}
namespace TestApp
{
[{|#0:AutoScene|}]
public partial class GameplayRoot : Node2D
{
}
}
""";
var test = new CSharpSourceGeneratorTest<AutoSceneGenerator, DefaultVerifier>
{
TestState =
{
Sources = { source }
},
DisabledDiagnostics = { "GF_Common_Trace_001" }
};
test.ExpectedDiagnostics.Add(new DiagnosticResult("GF_AutoBehavior_004", DiagnosticSeverity.Error)
.WithLocation(0)
.WithArguments("AutoSceneAttribute", "GameplayRoot", "a single string scene key argument"));
await test.RunAsync();
}
}