using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
namespace AtLangCompiler.Tests
{
[TestClass]
public sealed class SnapshotTests
{
///
/// When true, missing snapshots cause test failure instead of auto-generation.
/// Set UPDATE_SNAPSHOTS=true to auto-generate/update snapshots during development.
/// CI should always run without this variable to catch missing snapshots.
///
private static bool UpdateSnapshots =>
string.Equals(Environment.GetEnvironmentVariable("UPDATE_SNAPSHOTS"), "true", StringComparison.OrdinalIgnoreCase);
[TestMethod]
[Description("Runs the compiler against all samples and validates the output IL assembly matches the known snapshot.")]
[DynamicData(nameof(GetSamples), DynamicDataSourceType.Method, DynamicDataDisplayName = nameof(GetDisplayName))]
public void TestGeneratedILMatchesSnapshots(string atFilePath, string snapshotFilePath)
{
Assert.IsTrue(File.Exists(atFilePath), $"AT file not found: {atFilePath}");
string assemblyName = Path.GetFileNameWithoutExtension(atFilePath);
string tempFolder = Path.Combine(Path.GetTempPath(), nameof(SnapshotTests), Guid.NewGuid().ToString());
string tempAssembly = Path.Combine(tempFolder, assemblyName + ".dll");
Directory.CreateDirectory(tempFolder);
try
{
// Compile the .at file to IL
string atFileContents = File.ReadAllText(atFilePath);
Compiler.CompileToIL(atFileContents, tempAssembly);
Assert.IsTrue(File.Exists(tempAssembly), $"Compilation failed: {tempAssembly} was not generated.");
// Run ILDASM to get raw IL assembly
string ildasmOutputFile = Path.Combine(tempFolder, assemblyName + ".il");
RunILDASM(tempAssembly, ildasmOutputFile);
Assert.IsTrue(File.Exists(ildasmOutputFile), $"ILDASM failed: {ildasmOutputFile} was not generated.");
if (!File.Exists(snapshotFilePath))
{
if (UpdateSnapshots)
{
// Dev mode: auto-generate the missing snapshot
Debug.WriteLine($"Generating new snapshot: {snapshotFilePath}");
File.Copy(ildasmOutputFile, snapshotFilePath);
}
else
{
// CI mode: fail with instructions
Assert.Fail(
$"Snapshot file missing: {Path.GetFileName(snapshotFilePath)}. " +
$"Run tests with UPDATE_SNAPSHOTS=true to generate it, then commit the file to test/snapshots/.");
}
}
// Compare IL with snapshot
string generatedIL = RemoveIgnoredLines(File.ReadAllText(ildasmOutputFile));
string snapshotIL = RemoveIgnoredLines(File.ReadAllText(snapshotFilePath));
if (generatedIL != snapshotIL && UpdateSnapshots)
{
// Dev mode: auto-update the stale snapshot
Debug.WriteLine($"Updating snapshot: {snapshotFilePath}");
File.Copy(ildasmOutputFile, snapshotFilePath, overwrite: true);
snapshotIL = RemoveIgnoredLines(File.ReadAllText(snapshotFilePath));
}
Assert.AreEqual(snapshotIL, generatedIL,
$"IL mismatch for {Path.GetFileName(atFilePath)}. " +
$"If the change is intentional, run tests with UPDATE_SNAPSHOTS=true to update snapshots, then commit them.");
}
finally
{
// Cleanup the temporary folder
Directory.Delete(tempFolder, true);
}
}
///
/// Get all paths to samples and their IL snapshots.
///
public static IEnumerable