mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-13 00:38:42 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
198 lines
4.9 KiB
C#
198 lines
4.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
|
|
#nullable enable
|
|
|
|
namespace TestCompiler;
|
|
|
|
public interface IProgram
|
|
{
|
|
int Main( StringWriter output );
|
|
}
|
|
|
|
internal record BuildResult(
|
|
Assembly Assembly,
|
|
Assembly MethodBodyAssembly,
|
|
bool ILHotloadSupported,
|
|
bool HasSupportedAttribute,
|
|
(MethodBase Old, MethodBase New)[] ChangedMethods )
|
|
{
|
|
public IProgram CreateProgram( string typeName = "TestPackage.Program" )
|
|
{
|
|
var type = Assembly.GetType( typeName );
|
|
|
|
Assert.IsNotNull( type );
|
|
|
|
return (IProgram)Activator.CreateInstance( type )!;
|
|
}
|
|
}
|
|
|
|
internal class FastPathTestCompiler : IDisposable
|
|
{
|
|
public string Name { get; }
|
|
|
|
public ILHotload Hotload { get; }
|
|
public CompileGroup Group { get; }
|
|
public Compiler Compiler { get; }
|
|
public BaseFileSystem FileSystem { get; }
|
|
public BuildResult? LastResult { get; private set; }
|
|
|
|
public Compiler.Configuration Config
|
|
{
|
|
get => Compiler.GetConfiguration();
|
|
set => Compiler.SetConfiguration( value );
|
|
}
|
|
|
|
public FastPathTestCompiler( string sourceName )
|
|
{
|
|
Name = Path.GetFileNameWithoutExtension( sourceName );
|
|
|
|
Hotload = new ILHotload( "Test" );
|
|
Group = new CompileGroup( "Test" ) { AllowFastHotload = true };
|
|
Compiler = new Compiler( Group, Name );
|
|
Config = new Compiler.Configuration();
|
|
FileSystem = new MemoryFileSystem();
|
|
|
|
Compiler.AddSourceLocation( FileSystem );
|
|
|
|
Compiler.AddReference( "Sandbox.Compiling.Test" );
|
|
}
|
|
|
|
public async Task<BuildResult> BuildAsync( int version = 1, bool expectNotSupported = false )
|
|
{
|
|
var compileSuccessCallback = false;
|
|
|
|
Group.OnCompileSuccess = () => compileSuccessCallback = true;
|
|
|
|
var srcFile = new FileInfo( Path.Combine( "data", "code", "fastpath", $"{Name}.{version}.cs" ) );
|
|
|
|
await using ( var dstStream = FileSystem.OpenWrite( $"{Name}.cs" ) )
|
|
await using ( var srcStream = srcFile.OpenRead() )
|
|
{
|
|
await srcStream.CopyToAsync( dstStream );
|
|
}
|
|
|
|
Compiler.MarkForRecompile();
|
|
|
|
Assert.IsTrue( Compiler.NeedsBuild );
|
|
Assert.IsFalse( compileSuccessCallback );
|
|
|
|
await Group.BuildAsync();
|
|
|
|
Assert.IsTrue( compileSuccessCallback );
|
|
Assert.IsFalse( Compiler.NeedsBuild );
|
|
|
|
Assert.IsNotNull( Group.BuildResult );
|
|
Assert.IsTrue( Group.BuildResult.Success, Group.BuildResult.BuildDiagnosticsString() );
|
|
Assert.AreEqual( Group.BuildResult.Output.Count(), 1 );
|
|
|
|
var output = Group.BuildResult.Output.First();
|
|
|
|
var asm = Assembly.Load( output.AssemblyData );
|
|
|
|
var supported = ILHotload.TryFindChangedMethods( LastResult?.Assembly, LastResult?.MethodBodyAssembly, asm,
|
|
out var changes, out var unexpected, out var hasAttribute );
|
|
|
|
var result = new BuildResult( asm, asm, supported, hasAttribute, changes );
|
|
|
|
Console.WriteLine( $"Built VERSION {version}:" );
|
|
Console.WriteLine( $" ILHotloadSupported: {result.ILHotloadSupported}" );
|
|
Console.WriteLine( $" HasSupportedAttribute: {result.HasSupportedAttribute}" );
|
|
Console.WriteLine( $" ChangedMethods: {(result.ChangedMethods.Length == 0 ? "None" : "")}" );
|
|
|
|
foreach ( var (oldMethod, newMethod) in result.ChangedMethods )
|
|
{
|
|
Console.WriteLine( $" {newMethod.ToSimpleString()}" );
|
|
}
|
|
|
|
Console.WriteLine( $" UnexpectedChanges: {(unexpected.Length == 0 ? "None" : "")}" );
|
|
|
|
foreach ( var change in unexpected )
|
|
{
|
|
Console.WriteLine( $" {change.ToSimpleString()}" );
|
|
}
|
|
|
|
ILHotload.IgnoreAttachedDebugger = true;
|
|
|
|
try
|
|
{
|
|
if ( LastResult is null )
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if ( Hotload.Replace( LastResult.Assembly, LastResult.MethodBodyAssembly, result.Assembly ) )
|
|
{
|
|
Assert.IsTrue( result.ILHotloadSupported );
|
|
Assert.IsFalse( expectNotSupported );
|
|
|
|
result = result with { Assembly = LastResult.Assembly };
|
|
}
|
|
else
|
|
{
|
|
if ( result.ILHotloadSupported && System.Diagnostics.Debugger.IsAttached )
|
|
{
|
|
throw new Exception( "Can't perform ILHotload while debugging" );
|
|
}
|
|
|
|
if ( !expectNotSupported )
|
|
{
|
|
Assert.IsFalse( result.ILHotloadSupported );
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
finally
|
|
{
|
|
LastResult = result;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Compiler.Dispose();
|
|
Group.Dispose();
|
|
}
|
|
}
|
|
|
|
public partial class FastPathTest
|
|
{
|
|
private static int TestProgram( IProgram program, IEnumerable<string> expectedOutputLines )
|
|
{
|
|
return TestProgram( program, string.Join( "", expectedOutputLines.Select( x => $"{x}{Environment.NewLine}" ) ) );
|
|
}
|
|
|
|
private static int TestProgram( IProgram program, params string[] expectedOutputLines )
|
|
{
|
|
return TestProgram( program, expectedOutputLines.AsEnumerable() );
|
|
}
|
|
|
|
private static int TestProgram( IProgram program, string expectedOutput = "" )
|
|
{
|
|
var writer = new StringWriter();
|
|
|
|
try
|
|
{
|
|
var exitCode = program.Main( writer );
|
|
|
|
Console.WriteLine( $"Exit code: {exitCode}" );
|
|
|
|
Assert.AreEqual( expectedOutput, writer.ToString() );
|
|
|
|
return exitCode;
|
|
}
|
|
finally
|
|
{
|
|
Console.WriteLine( "Output:" );
|
|
|
|
foreach ( var line in writer.ToString().Split( Environment.NewLine ) )
|
|
{
|
|
Console.WriteLine( $" {line}" );
|
|
}
|
|
}
|
|
}
|
|
}
|