mirror of
https://github.com/SK-la/osu-framework.git
synced 2026-03-13 11:20:31 +00:00
113 lines
5.1 KiB
C#
113 lines
5.1 KiB
C#
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
// See the LICENCE file in the repository root for full licence text.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
using osu.Framework.SourceGeneration.Generators;
|
|
|
|
namespace osu.Framework.SourceGeneration.Tests.Verifiers
|
|
{
|
|
public partial class CSharpMultiPhaseSourceGeneratorVerifier<TSourceGenerator> where TSourceGenerator : AbstractIncrementalGenerator, new()
|
|
{
|
|
public class Test
|
|
{
|
|
private GeneratorDriver driver;
|
|
private readonly TSourceGenerator generator;
|
|
private readonly (string filename, string content)[] commonSources;
|
|
private readonly (string filename, string content)[] commonGenerated;
|
|
private readonly List<List<(string filename, string content)>> multiPhaseSources;
|
|
private readonly List<List<(string filename, string content)>> multiPhaseGenerated;
|
|
|
|
public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.Default;
|
|
|
|
public event Action<int>? PhaseChanged;
|
|
public event Action? PhaseCompleted;
|
|
|
|
public Test(
|
|
(string filename, string content)[] commonSources,
|
|
(string filename, string content)[] commonGenerated,
|
|
List<List<(string filename, string content)>> multiPhaseSources,
|
|
List<List<(string filename, string content)>> multiPhaseGenerated)
|
|
{
|
|
driver = CSharpGeneratorDriver.Create(generator = new TSourceGenerator());
|
|
driver = driver.WithUpdatedParseOptions(CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion));
|
|
|
|
this.commonSources = commonSources;
|
|
this.commonGenerated = commonGenerated;
|
|
this.multiPhaseSources = multiPhaseSources;
|
|
this.multiPhaseGenerated = multiPhaseGenerated;
|
|
}
|
|
|
|
public void AddStatisticsVerification((int syntaxTargetCreated, int semanticTargetCreated, int emitHits)[] expectedStatistics)
|
|
{
|
|
int phase = 0;
|
|
int syntaxTargetCreated = 0;
|
|
int semanticTargetCreated = 0;
|
|
int emitHits = 0;
|
|
|
|
PhaseChanged += p =>
|
|
{
|
|
phase = p;
|
|
syntaxTargetCreated = 0;
|
|
semanticTargetCreated = 0;
|
|
emitHits = 0;
|
|
};
|
|
|
|
generator.EventDriver.SyntaxTargetCreated += _ => syntaxTargetCreated++;
|
|
generator.EventDriver.SemanticTargetCreated += _ => semanticTargetCreated++;
|
|
generator.EventDriver.Emit += _ => emitHits++;
|
|
|
|
PhaseCompleted += () =>
|
|
{
|
|
var expected = expectedStatistics[phase];
|
|
var actual = (syntaxTargetCreated, semanticTargetCreated, emitHits);
|
|
|
|
if (actual != expected)
|
|
throw new Xunit.Sdk.XunitException($"Phase {phase}: Expected statistics {expected} but got {actual}.");
|
|
};
|
|
}
|
|
|
|
public void Verify()
|
|
{
|
|
IncrementalCompilation compilation = new IncrementalCompilation();
|
|
|
|
foreach (var s in commonSources)
|
|
compilation.AddOrUpdateSource(s.filename, s.content);
|
|
|
|
for (int phase = 0; phase < multiPhaseSources.Count; phase++)
|
|
{
|
|
PhaseChanged?.Invoke(phase);
|
|
List<(string filename, string content)> sources = multiPhaseSources[phase];
|
|
List<(string filename, string content)> generated = multiPhaseGenerated[phase];
|
|
generated.AddRange(commonGenerated);
|
|
|
|
// Remove sources from previous phase that are not existing in the current phase
|
|
if (phase > 0)
|
|
{
|
|
foreach (var (filename, _) in multiPhaseSources[phase - 1].Where(old => sources.All(@new => @new.filename != old.filename)))
|
|
compilation.RemoveSource(filename);
|
|
}
|
|
|
|
// Add sources for the current phase
|
|
foreach (var (filename, content) in sources)
|
|
{
|
|
compilation.AddOrUpdateSource(filename, content);
|
|
}
|
|
|
|
// Run the generator. This will update compilation internally and return the results of the
|
|
// run, which we use later to verify the generated sources. We pass the driver as ref since
|
|
// driver itself is immutable and creates a new driver instance per run with new information.
|
|
var results = compilation.RunGenerators(ref driver);
|
|
|
|
results.VerifyZeroDiagnostics();
|
|
results.VerifyMultiPhaseGeneratedSources(generated.ToArray(), phase);
|
|
PhaseCompleted?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|