Files
sbox-public/engine/Sandbox.Compiling.Test/Tests/CodeArchiveTest.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

189 lines
7.2 KiB
C#

using System;
namespace TestCompiler;
[TestClass]
public partial class CodeArchiveTest
{
static void AreEqual( CodeArchive a, CodeArchive b )
{
Assert.AreEqual( a.Configuration.RootNamespace, b.Configuration.RootNamespace );
Assert.AreEqual( a.Configuration.DefineConstants, b.Configuration.DefineConstants );
Assert.AreEqual( a.Configuration.NoWarn, b.Configuration.NoWarn );
Assert.AreEqual( a.Configuration.WarningsAsErrors, b.Configuration.WarningsAsErrors );
Assert.AreEqual( a.Configuration.Nullables, b.Configuration.Nullables );
Assert.AreEqual( a.Configuration.ReleaseMode, b.Configuration.ReleaseMode );
Assert.AreEqual( a.Configuration.Whitelist, b.Configuration.Whitelist );
Assert.AreEqual( a.Configuration.Unsafe, b.Configuration.Unsafe );
Assert.AreEqual( a.References.Count(), b.References.Count() );
Assert.AreEqual( a.SyntaxTrees.Count(), b.SyntaxTrees.Count() );
Assert.AreEqual( a.FileMap.Count(), b.FileMap.Count() );
}
static async Task<CompilerOutput> CompileAndTest( CodeArchive a )
{
var group = new CompileGroup( "Test" );
var compiler = group.GetOrCreateCompiler( "test" );
compiler.UpdateFromArchive( a );
await group.BuildAsync();
return compiler.Output;
}
/// <summary>
/// As simple as things could be. Create a compile group with a single compiler.
/// </summary>
[TestMethod]
public async Task SingleCompiler()
{
// Compile some shit
var codePath = System.IO.Path.GetFullPath( "data/code/base" );
var group = new CompileGroup( "Test" );
var compiler = group.CreateCompiler( "test", codePath, new Compiler.Configuration() );
await group.BuildAsync();
// make sure it compiled right
var o = compiler.Output;
Assert.IsNotNull( o );
Assert.IsNotNull( o.Compiler );
Assert.IsNotNull( o.AssemblyData );
Assert.IsNotNull( o.XmlDocumentation );
Assert.IsNotNull( o.Diagnostics );
Assert.IsNull( o.Exception );
// make sure the archive got created right
Assert.IsNotNull( o.Archive );
Assert.IsNotNull( o.Archive.SyntaxTrees );
Assert.AreNotEqual( 0, o.Archive.SyntaxTrees.Count() );
Assert.AreNotEqual( 0, o.Archive.FileMap.Count() );
Assert.AreNotEqual( 0, o.Archive.References.Count() );
Assert.IsTrue( o.Archive.References.Count() < 50, "Make sure framework references aren't finding their way into References!" );
// convert the archive to bytes gzipped json, mostly
var data = o.Archive.Serialize();
Assert.IsNotNull( data );
// create a new code archive using that data
var a = new CodeArchive();
a.Deserialize( data );
AreEqual( a, o.Archive );
// compile this code archive
var p = await CompileAndTest( a );
// make sure result is identical(ish)
Assert.AreEqual( o.Successful, p.Successful );
Assert.AreEqual( o.AssemblyData.Length, p.AssemblyData.Length );
Assert.AreEqual( o.XmlDocumentation, p.XmlDocumentation );
Assert.AreEqual( o.Diagnostics.Count, p.Diagnostics.Count );
}
/// <summary>
/// As simple as things could be. Create a compile group with a single compiler.
/// </summary>
[TestMethod]
public async Task SingleCompilerWithServer()
{
var codePath = System.IO.Path.GetFullPath( "data/code/base_with_server" );
var group = new CompileGroup( "TestServer" );
var compilerSettings = new Compiler.Configuration();
compilerSettings.StripDisabledTextTrivia = true;
var compiler = group.CreateCompiler( "test", codePath, compilerSettings );
await group.BuildAsync();
// make sure it compiled right
var o = compiler.Output;
Assert.IsNotNull( o );
Assert.IsNotNull( o.Archive );
Assert.IsNotNull( o.Archive.SyntaxTrees );
// Find all .Server.cs files in the syntax trees
var serverFiles = o.Archive.SyntaxTrees
.Where( x => x.FilePath.EndsWith( ".Server.cs", StringComparison.OrdinalIgnoreCase ) )
.ToArray();
// Make sure we found at least one server file
Assert.IsTrue( serverFiles.Length > 0, "No .Server.cs files found in test data" );
// Check each server file's contents in CLIENT build
foreach ( var serverFile in serverFiles )
{
var text = serverFile.GetText().ToString().Trim();
var lines = text.Split( new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries );
// Should only have #if SERVER and #endif - no content
Assert.AreEqual( 2, lines.Length, $"Client server file {serverFile.FilePath} should only contain #if SERVER and #endif" );
Assert.AreEqual( "#if SERVER", lines[0].Trim(), $"Server file {serverFile.FilePath} should start with #if SERVER" );
Assert.AreEqual( "#endif", lines[1].Trim(), $"Server file {serverFile.FilePath} should end with #endif" );
}
// Configure server build
var serverSettings = new Compiler.Configuration();
serverSettings.ReplacementDirectives[".Server.cs"] = "SERVER";
serverSettings.DefineConstants += ";SERVER";
var serverCompiler = group.CreateCompiler( "test.server", codePath, serverSettings );
await group.BuildAsync();
// make sure server build compiled right
var serverOutput = serverCompiler.Output;
Assert.IsNotNull( serverOutput );
Assert.IsTrue( serverOutput.Successful, "Server build should compile successfully" );
// Check server build files - should contain actual code
var serverBuildFiles = serverOutput.Archive.SyntaxTrees
.Where( x => x.FilePath.EndsWith( ".Server.cs", StringComparison.OrdinalIgnoreCase ) )
.ToArray();
foreach ( var serverFile in serverBuildFiles )
{
var text = serverFile.GetText().ToString().Trim();
var lines = text.Split( new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries );
// Should have content between directives
Assert.IsTrue( lines.Length >= 3, $"Server build file {serverFile.FilePath} should have content between directives" );
Assert.AreEqual( "#if SERVER", lines[0].Trim(), $"Server file {serverFile.FilePath} should start with #if SERVER" );
Assert.AreEqual( "#endif", lines[lines.Length - 1].Trim(), $"Server file {serverFile.FilePath} should end with #endif" );
}
Assert.AreEqual( serverFiles.Length, serverBuildFiles.Length,
"Server build should have same number of .Server.cs files" );
}
/// <summary>
/// <see cref="Compiler.UpdateFromArchive"/> needs to copy references from the archive, otherwise
/// assemblies can be loaded in the wrong order when players join a host. This was causing deserialization
/// errors, with old versions of assemblies being referenced by other currently loaded assemblies.
/// </summary>
[TestMethod]
public void ReferencesCopied()
{
var group = new CompileGroup( "Test" );
// Create base compiler
group.CreateCompiler( "base", System.IO.Path.GetFullPath( "data/code/base" ), new Compiler.Configuration() );
// Create dependent compiler
var dependantCompiler = group.CreateCompiler( "dependant", System.IO.Path.GetFullPath( "data/code/dependant" ), new Compiler.Configuration() );
// We haven't referenced base compiler yet
Assert.IsFalse( dependantCompiler.HasReference( "package.base", true ) );
// Update from archive with a reference to package.base
var archive = new CodeArchive();
archive.References.Add( "package.base" );
dependantCompiler.UpdateFromArchive( archive );
// We should have a reference to package.base now
Assert.IsTrue( dependantCompiler.HasReference( "package.base", true ) );
}
}