Skip to content

Commit 8e69d19

Browse files
committed
Add unit tests for CommandImplGenerator functionalityAdd tests for CommandImplGenerator with sample source code
This commit introduces unit tests for the `CommandImplGenerator` to validate its output. The tests include a sample command source and verify the correctness of the generated implementations, such as `TestCommandImpl`, `CommandsModule`, and `RootCommandImpl`. It ensures compatibility with required dependencies and adheres to .NET 9.0 standards.
1 parent 15b401d commit 8e69d19

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
using System.CommandLine;
2+
using GitVersion.Infrastructure;
3+
using Microsoft.CodeAnalysis;
4+
using Microsoft.CodeAnalysis.CSharp.Testing;
5+
using Microsoft.CodeAnalysis.Testing;
6+
7+
namespace GitVersion.Cli.Generator.Tests;
8+
9+
public class CommandImplGeneratorTests
10+
{
11+
/*language=cs*/
12+
private const string TestCommandSourceCode =
13+
"""
14+
using System.Threading;
15+
using System.Threading.Tasks;
16+
using GitVersion.Infrastructure;
17+
18+
namespace GitVersion.Commands;
19+
20+
public record TestCommandSettings
21+
{
22+
[Option("--output-file", "The output file")]
23+
public required string OutputFile { get; init; }
24+
}
25+
26+
[CommandAttribute("test", "Test description.")]
27+
public class TestCommand(ILogger logger): ICommand<TestCommandSettings>
28+
{
29+
public Task<int> InvokeAsync(TestCommandSettings settings, CancellationToken cancellationToken = default)
30+
{
31+
return Task.FromResult(0);
32+
}
33+
}
34+
35+
""";
36+
37+
/*language=cs*/
38+
private const string ExpectedCommandImplText =
39+
$$"""
40+
{{Content.GeneratedHeader}}
41+
using System.CommandLine;
42+
using System.CommandLine.Binding;
43+
using System.Threading;
44+
using System.Threading.Tasks;
45+
46+
using GitVersion.Commands;
47+
48+
namespace GitVersion.Generated;
49+
50+
public class TestCommandImpl : Command, ICommandImpl
51+
{
52+
public string CommandName => nameof(TestCommandImpl);
53+
public string ParentCommandName => string.Empty;
54+
// Options list
55+
protected readonly Option<string> OutputFileOption;
56+
57+
public TestCommandImpl(TestCommand command)
58+
: base("test", "Test description.")
59+
{
60+
OutputFileOption = new Option<string>("--output-file", [])
61+
{
62+
Required = false,
63+
Description = "The output file",
64+
};
65+
Add(OutputFileOption);
66+
67+
this.SetAction(Run);
68+
return;
69+
70+
Task<int> Run(ParseResult parseResult, CancellationToken cancellationToken)
71+
{
72+
var settings = new TestCommandSettings
73+
{
74+
OutputFile = parseResult.GetValue(OutputFileOption),
75+
};
76+
return command.InvokeAsync(settings, cancellationToken);
77+
}
78+
}
79+
}
80+
""";
81+
82+
/*language=cs*/
83+
private const string ExpectedCommandsModuleText =
84+
$$"""
85+
{{Content.GeneratedHeader}}
86+
using System.CommandLine;
87+
using GitVersion.Infrastructure;
88+
using GitVersion.Commands;
89+
using GitVersion;
90+
91+
namespace GitVersion.Generated;
92+
93+
public class CommandsModule : IGitVersionModule
94+
{
95+
public void RegisterTypes(IContainerRegistrar services)
96+
{
97+
services.AddSingleton<RootCommandImpl>();
98+
services.AddSingleton<TestCommand>();
99+
services.AddSingleton<ICommandImpl, TestCommandImpl>();
100+
}
101+
}
102+
""";
103+
104+
/*language=cs*/
105+
private const string ExpectedRootCommandImplText =
106+
$$"""
107+
{{Content.GeneratedHeader}}
108+
using System.Collections.Generic;
109+
using System.CommandLine;
110+
using System.Linq;
111+
112+
using GitVersion;
113+
namespace GitVersion.Generated;
114+
115+
public class RootCommandImpl : RootCommand
116+
{
117+
public RootCommandImpl(IEnumerable<ICommandImpl> commands)
118+
{
119+
var map = commands.ToDictionary(c => c.CommandName);
120+
foreach (var command in map.Values)
121+
{
122+
AddCommand(command, map);
123+
}
124+
}
125+
private void AddCommand(ICommandImpl command, IDictionary<string, ICommandImpl> map)
126+
{
127+
if (!string.IsNullOrWhiteSpace(command.ParentCommandName))
128+
{
129+
var parent = map[command.ParentCommandName] as Command;
130+
parent?.Add((Command)command);
131+
}
132+
else
133+
{
134+
Add((Command)command);
135+
}
136+
}
137+
}
138+
""";
139+
140+
[Test]
141+
public async Task ValidateGeneratedCommandImplementation()
142+
{
143+
var generatorType = typeof(CommandImplGenerator);
144+
var sourceGeneratorTest = new CSharpSourceGeneratorTest<CommandImplGenerator, DefaultVerifier>
145+
{
146+
TestState =
147+
{
148+
Sources =
149+
{
150+
(generatorType, "TestCommand.cs", TestCommandSourceCode)
151+
},
152+
GeneratedSources =
153+
{
154+
(generatorType,"TestCommandImpl.g.cs", ExpectedCommandImplText),
155+
(generatorType,"CommandsModule.g.cs", ExpectedCommandsModuleText),
156+
(generatorType,"RootCommandImpl.g.cs", ExpectedRootCommandImplText),
157+
},
158+
ReferenceAssemblies = ReferenceAssemblies.Net.Net90,
159+
AdditionalReferences =
160+
{
161+
MetadataReference.CreateFromFile(typeof(ILogger).Assembly.Location),
162+
MetadataReference.CreateFromFile(typeof(RootCommand).Assembly.Location),
163+
MetadataReference.CreateFromFile(typeof(CommandAttribute).Assembly.Location),
164+
}
165+
}
166+
};
167+
168+
await sourceGeneratorTest.RunAsync();
169+
}
170+
}

0 commit comments

Comments
 (0)