2024-01-29 21:42:06 -06:00
|
|
|
using Sprache;
|
2024-01-29 21:57:00 -06:00
|
|
|
using Microsoft.Iris.Asm;
|
2024-01-29 22:09:51 -06:00
|
|
|
using Xunit.Abstractions;
|
2024-01-30 23:30:42 -06:00
|
|
|
using Microsoft.Iris.Markup;
|
2024-01-31 19:48:13 -06:00
|
|
|
using UIX.Test.Fixtures;
|
2024-02-03 20:51:54 -06:00
|
|
|
using Microsoft.Iris;
|
2024-02-10 21:39:07 -06:00
|
|
|
using Microsoft.Iris.Session;
|
2024-02-16 20:40:14 -06:00
|
|
|
using Microsoft.Iris.Debug;
|
2024-01-29 21:42:06 -06:00
|
|
|
|
|
|
|
|
namespace UIX.Test;
|
|
|
|
|
|
2024-01-31 19:48:13 -06:00
|
|
|
[Collection(MarkupSystemCollection.Name)]
|
2024-01-29 22:09:51 -06:00
|
|
|
public class Assembly(ITestOutputHelper output)
|
2024-01-29 21:42:06 -06:00
|
|
|
{
|
|
|
|
|
[Fact]
|
2024-01-31 19:51:55 -06:00
|
|
|
public void Parse()
|
2024-01-29 21:42:06 -06:00
|
|
|
{
|
|
|
|
|
const string code =
|
|
|
|
|
"""
|
2024-02-11 20:39:21 -06:00
|
|
|
.export Default 0 UI
|
|
|
|
|
.export Alt 0 UI
|
2024-02-08 13:50:51 -06:00
|
|
|
|
2024-02-11 20:39:21 -06:00
|
|
|
.import-type UI
|
|
|
|
|
.import-type Dictionary
|
2024-01-30 23:30:42 -06:00
|
|
|
.import-ns assembly://UIX/Microsoft.Iris as iris
|
2024-02-08 13:50:51 -06:00
|
|
|
.import-type iris:Command
|
2024-02-11 20:39:21 -06:00
|
|
|
.import-type String
|
|
|
|
|
.import-type ViewItem
|
|
|
|
|
.import-type Text
|
|
|
|
|
.import-type Color
|
|
|
|
|
.import-type Font
|
2024-02-16 20:37:47 -06:00
|
|
|
.import-mbrs UI{Locals, Content}
|
|
|
|
|
.import-mbrs Text{Color, Content, Font}
|
2024-02-05 09:23:46 -06:00
|
|
|
|
2024-07-07 15:34:27 -05:00
|
|
|
.constant const0 = Color.str(255, 255, 0, 0)
|
|
|
|
|
.constant const1 = String.str(Howdy from Microsoft.Iris!)
|
|
|
|
|
.constant const2 = String.str(SelectCommand)
|
|
|
|
|
.constant const3 = Color.str(255, 0, 0, 255)
|
|
|
|
|
.constant const4 = Font.str(JetBrains Mono)
|
|
|
|
|
.constant const5 = String.str(This is some blue text)
|
2024-02-05 09:23:46 -06:00
|
|
|
.section object
|
2024-02-11 20:39:21 -06:00
|
|
|
|
|
|
|
|
Default_cont:
|
|
|
|
|
COBJ 5
|
|
|
|
|
PSHC @const0
|
2024-01-29 21:42:06 -06:00
|
|
|
PINI 2
|
2024-02-11 20:39:21 -06:00
|
|
|
PSHC @const1
|
|
|
|
|
PINI 3
|
|
|
|
|
PINI 1
|
2024-01-29 21:42:06 -06:00
|
|
|
RETV
|
2024-02-11 20:39:21 -06:00
|
|
|
Default_locl:
|
|
|
|
|
COBJ 2
|
|
|
|
|
PDAD 0, @const2
|
|
|
|
|
RETV
|
|
|
|
|
Alt_cont:
|
|
|
|
|
COBJ 5
|
|
|
|
|
PSHC @const3
|
|
|
|
|
PINI 2
|
|
|
|
|
PSHC @const4
|
|
|
|
|
PINI 4
|
|
|
|
|
PSHC @const5
|
|
|
|
|
PINI 3
|
|
|
|
|
PINI 1
|
|
|
|
|
RETV
|
|
|
|
|
Alt_locl:
|
2024-01-29 21:42:06 -06:00
|
|
|
RETV
|
|
|
|
|
""";
|
|
|
|
|
|
|
|
|
|
var ast = Lexer.Program.Parse(code);
|
2024-01-29 22:09:51 -06:00
|
|
|
output.WriteLine(ast.ToString());
|
|
|
|
|
|
2024-01-29 21:42:06 -06:00
|
|
|
Assert.NotNull(ast);
|
2024-02-16 20:37:47 -06:00
|
|
|
Assert.Equal(20, ast.Directives.Count());
|
2024-02-11 20:39:21 -06:00
|
|
|
Assert.Equal(24, ast.Code.Count());
|
2024-01-29 21:42:06 -06:00
|
|
|
}
|
2024-01-30 23:30:42 -06:00
|
|
|
|
2024-02-10 21:39:07 -06:00
|
|
|
[Theory]
|
|
|
|
|
[InlineData("text")]
|
|
|
|
|
public async Task ReassembleFromUIB(string fileNameWithoutExtension)
|
|
|
|
|
{
|
|
|
|
|
using TempFile uibFile = new($"{fileNameWithoutExtension}.uib", ".uib");
|
|
|
|
|
await uibFile.InitAsync();
|
|
|
|
|
|
|
|
|
|
var uixaPath = Path.ChangeExtension(uibFile.Path, ".uixa");
|
|
|
|
|
var uibPathAc = Path.ChangeExtension(uibFile.Path, ".g.uib");
|
|
|
|
|
|
2024-02-16 20:40:14 -06:00
|
|
|
// Configure debugging stuff
|
|
|
|
|
ErrorManager.OnErrors += (errors) =>
|
|
|
|
|
{
|
|
|
|
|
foreach (ErrorRecord error in errors)
|
|
|
|
|
output.WriteLine($"Error at (L{error.Line}, C{error.Column}): {error.Message}");
|
|
|
|
|
};
|
|
|
|
|
TraceSettings.Current.SetCategoryLevel(TraceCategory.Markup, byte.MaxValue);
|
|
|
|
|
TraceSettings.Current.SetCategoryLevel(TraceCategory.MarkupCompiler, byte.MaxValue);
|
|
|
|
|
TraceSettings.Current.OnWriteLine += output.WriteLine;
|
|
|
|
|
|
2024-02-10 21:39:07 -06:00
|
|
|
// Disassemble the compiled UIX
|
|
|
|
|
var sourceLoadResult = MarkupSystem.ResolveLoadResult($"file://{uibFile.Path}", MarkupSystem.RootIslandId);
|
|
|
|
|
var disassembly = Disassembler.Load(sourceLoadResult as MarkupLoadResult);
|
|
|
|
|
var disassemblyText = disassembly.Write();
|
|
|
|
|
File.WriteAllText(uixaPath, disassemblyText);
|
|
|
|
|
|
|
|
|
|
// Compile the generated Assembly source
|
|
|
|
|
CompilerInput compilerInput = new()
|
|
|
|
|
{
|
|
|
|
|
SourceFileName = uixaPath,
|
|
|
|
|
OutputFileName = uibPathAc
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
output.WriteLine($"Expected: {uibFile.Path}");
|
|
|
|
|
output.WriteLine($"Actual: {compilerInput.OutputFileName}");
|
|
|
|
|
|
|
|
|
|
// Assemble the disassembly result
|
|
|
|
|
var success = MarkupCompiler.Compile([compilerInput], default);
|
|
|
|
|
Assert.True(success);
|
|
|
|
|
|
|
|
|
|
// Compare the original UIB file to the reassembled UIB
|
|
|
|
|
var uibBytesEx = await File.ReadAllBytesAsync(uibFile.Path);
|
|
|
|
|
var uibBytesAc = await File.ReadAllBytesAsync(compilerInput.OutputFileName);
|
2024-02-16 20:40:14 -06:00
|
|
|
//Assert.Equal(uibBytesEx, uibBytesAc);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var actualLoadResult = MarkupSystem.ResolveLoadResult($"file://{compilerInput.OutputFileName}", (uint)Random.Shared.Next());
|
2024-02-18 22:25:30 -06:00
|
|
|
actualLoadResult.FullLoad();
|
|
|
|
|
AssertEx.DeepEquivalent(sourceLoadResult, actualLoadResult);
|
2024-02-16 20:40:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Theory]
|
|
|
|
|
[InlineData("testA")]
|
|
|
|
|
public async Task ReassembleFromUIX(string fileNameWithoutExtension)
|
|
|
|
|
{
|
|
|
|
|
using TempFile uixFile = new($"{fileNameWithoutExtension}.uix", ".uix");
|
|
|
|
|
await uixFile.InitAsync();
|
|
|
|
|
|
|
|
|
|
var uixaPath = Path.ChangeExtension(uixFile.Path, ".uixa");
|
|
|
|
|
var uibPathEx = Path.ChangeExtension(uixFile.Path, ".uib");
|
|
|
|
|
var uibPathAc = Path.ChangeExtension(uixFile.Path, ".g.uib");
|
|
|
|
|
|
|
|
|
|
// Configure debugging stuff
|
|
|
|
|
ErrorManager.OnErrors += (errors) =>
|
|
|
|
|
{
|
|
|
|
|
foreach (ErrorRecord error in errors)
|
|
|
|
|
output.WriteLine($"Error at (L{error.Line}, C{error.Column}): {error.Message}");
|
|
|
|
|
};
|
|
|
|
|
TraceSettings.Current.SetCategoryLevel(TraceCategory.Markup, byte.MaxValue);
|
|
|
|
|
TraceSettings.Current.SetCategoryLevel(TraceCategory.MarkupCompiler, byte.MaxValue);
|
|
|
|
|
TraceSettings.Current.OnWriteLine += output.WriteLine;
|
|
|
|
|
|
|
|
|
|
CompilerInput uixCompilerInput = new()
|
|
|
|
|
{
|
|
|
|
|
SourceFileName = uixFile.Path,
|
|
|
|
|
OutputFileName = uibPathEx
|
|
|
|
|
};
|
|
|
|
|
CompilerInput asmCompilerInput = new()
|
|
|
|
|
{
|
|
|
|
|
SourceFileName = uixaPath,
|
|
|
|
|
OutputFileName = uibPathAc
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
output.WriteLine($"Source: {uixFile.Path}");
|
|
|
|
|
output.WriteLine($"Expected: {uibPathEx}");
|
|
|
|
|
output.WriteLine($"Actual: {uibPathAc}");
|
|
|
|
|
|
|
|
|
|
ErrorManager.OnErrors += (errors) =>
|
|
|
|
|
{
|
|
|
|
|
foreach (ErrorRecord error in errors)
|
|
|
|
|
output.WriteLine($"Error at (L{error.Line}, C{error.Column}): {error.Message}");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Compile the UIX source
|
|
|
|
|
var uixSuccess = MarkupCompiler.Compile([uixCompilerInput], default);
|
|
|
|
|
Assert.True(uixSuccess);
|
|
|
|
|
|
|
|
|
|
// Disassemble the compiled UIX
|
|
|
|
|
var sourceLoadResult = MarkupSystem.ResolveLoadResult($"file://{uixFile.Path}", MarkupSystem.RootIslandId);
|
|
|
|
|
var disassembly = Disassembler.Load(sourceLoadResult as MarkupLoadResult);
|
|
|
|
|
var disassemblyText = disassembly.Write();
|
|
|
|
|
File.WriteAllText(uixaPath, disassemblyText);
|
|
|
|
|
|
|
|
|
|
// Compile the generated Assembly source
|
|
|
|
|
var asmSuccess = MarkupCompiler.Compile([asmCompilerInput], default);
|
|
|
|
|
Assert.True(asmSuccess);
|
|
|
|
|
|
2024-02-18 22:25:30 -06:00
|
|
|
// Load assembled UIB and compare with original result
|
|
|
|
|
var actualLoadResult = MarkupSystem.ResolveLoadResult($"file://{uibPathAc}", (uint)Random.Shared.Next());
|
|
|
|
|
actualLoadResult.FullLoad();
|
|
|
|
|
|
|
|
|
|
AssertEx.DeepEquivalent(sourceLoadResult, actualLoadResult);
|
|
|
|
|
|
|
|
|
|
if (false)
|
|
|
|
|
{
|
|
|
|
|
// Compare the original UIB file to the reassembled UIB
|
|
|
|
|
var uibBytesEx = await File.ReadAllBytesAsync(uibPathEx);
|
|
|
|
|
var uibBytesAc = await File.ReadAllBytesAsync(asmCompilerInput.OutputFileName);
|
|
|
|
|
Assert.Equal(uibBytesEx, uibBytesAc);
|
|
|
|
|
}
|
2024-02-10 21:39:07 -06:00
|
|
|
}
|
|
|
|
|
|
2024-02-10 19:19:40 -06:00
|
|
|
[Theory]
|
|
|
|
|
[InlineData("testA")]
|
|
|
|
|
public async Task Assemble(string fileNameWithoutExtension)
|
2024-02-03 20:51:54 -06:00
|
|
|
{
|
2024-02-10 21:39:07 -06:00
|
|
|
using TempFile asmFile = new($"{fileNameWithoutExtension}.uixa", ".uixa");
|
|
|
|
|
await asmFile.InitAsync();
|
2024-02-03 20:51:54 -06:00
|
|
|
|
|
|
|
|
CompilerInput[] compilerInputs = [
|
|
|
|
|
new()
|
|
|
|
|
{
|
2024-02-10 21:39:07 -06:00
|
|
|
SourceFileName = asmFile.Path,
|
|
|
|
|
OutputFileName = Path.ChangeExtension(asmFile.Path, ".uib")
|
2024-02-03 20:51:54 -06:00
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
foreach (var compilerInput in compilerInputs)
|
|
|
|
|
output.WriteLine(compilerInput.OutputFileName);
|
|
|
|
|
|
2024-02-10 21:39:07 -06:00
|
|
|
ErrorManager.OnErrors += (errors) =>
|
|
|
|
|
{
|
|
|
|
|
foreach (ErrorRecord error in errors)
|
2024-02-10 23:03:57 -06:00
|
|
|
{
|
|
|
|
|
var errorTypeText = error.Warning ? "Warning" : "Error";
|
|
|
|
|
output.WriteLine($"{errorTypeText} at (L{error.Line}, C{error.Column}): {error.Message}");
|
|
|
|
|
}
|
2024-02-10 21:39:07 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var success = MarkupCompiler.Compile(compilerInputs, default);
|
|
|
|
|
Assert.True(success);
|
2024-02-16 20:40:14 -06:00
|
|
|
|
|
|
|
|
var compiledLoadResult = MarkupSystem.ResolveLoadResult($"file://{compilerInputs[0].OutputFileName}", MarkupSystem.RootIslandId);
|
|
|
|
|
compiledLoadResult.FullLoad();
|
2024-02-03 20:51:54 -06:00
|
|
|
}
|
|
|
|
|
|
2024-01-31 19:48:13 -06:00
|
|
|
[Theory]
|
|
|
|
|
[InlineData("text.uib")]
|
|
|
|
|
[InlineData("text.uix")]
|
|
|
|
|
[InlineData("testA.uix")]
|
|
|
|
|
[InlineData("testB.uix")]
|
2024-01-31 20:07:01 -06:00
|
|
|
public async Task Disassemble(string testResourceName)
|
2024-01-30 23:30:42 -06:00
|
|
|
{
|
2024-01-31 20:07:01 -06:00
|
|
|
using TempFile tempFile = new(testResourceName);
|
|
|
|
|
await tempFile.InitAsync();
|
2024-01-30 23:30:42 -06:00
|
|
|
|
2024-01-31 20:07:01 -06:00
|
|
|
string uri = "file://" + tempFile.Path;
|
2024-01-30 23:30:42 -06:00
|
|
|
|
|
|
|
|
var sourceLoadResult = MarkupSystem.ResolveLoadResult(uri, MarkupSystem.RootIslandId);
|
|
|
|
|
var dis = Disassembler.Load(sourceLoadResult as MarkupLoadResult);
|
|
|
|
|
|
2024-01-31 19:48:13 -06:00
|
|
|
var disText = dis.Write();
|
|
|
|
|
output.WriteLine(disText);
|
2024-01-30 23:30:42 -06:00
|
|
|
}
|
2024-01-29 21:42:06 -06:00
|
|
|
}
|