public void CreateOperation_NoInputOrOutput() { // Register the test listener var testListener = new TestTraceListener(); using var scopedTraceListener = new ScopedTraceListenerRegister(testListener); var fileSystemState = new FileSystemState(); var readAccessList = new List <Path>(); var writeAccessList = new List <Path>(); var uut = new OperationGraphGenerator(fileSystemState, readAccessList, writeAccessList); uut.CreateOperation( "Do Stuff", new Path("DoStuff.exe"), "do stuff", new Path("C:/WorkingDir/"), new List <Path>(), new List <Path>()); // Verify expected logs Assert.Equal( new List <string>() { "DIAG: Create Operation: Do Stuff", "DIAG: Read Access Subset:", "DIAG: Write Access Subset:", }, testListener.GetMessages()); }
public void Execute() { // Register the test systems var testListener = new TestTraceListener(); using (var scopedTraceListener = new ScopedTraceListenerRegister(testListener)) { // Setup the input build state var buildState = new MockBuildState(); var state = buildState.ActiveState; // Set the sdks var sdks = new ValueList(); sdks.Add(new Value(new ValueTable() { { "Name", new Value("Roslyn") }, { "Properties", new Value(new ValueTable() { { "ToolsRoot", new Value("C:/Roslyn/ToolsRoot/") } }) }, })); // Setup parameters table var parametersTable = new ValueTable(); state.Add("Parameters", new Value(parametersTable)); parametersTable.Add("SDKs", new Value(sdks)); parametersTable.Add("System", new Value("win32")); parametersTable.Add("Architecture", new Value("x64")); // Setup build table var buildTable = new ValueTable(); state.Add("Build", new Value(buildTable)); var factory = new ValueFactory(); var uut = new ResolveToolsTask(buildState, factory); uut.Execute(); // Verify expected logs Assert.Equal( new List <string>() { }, testListener.GetMessages()); // Verify build state var expectedBuildOperations = new List <BuildOperation>(); Assert.Equal( expectedBuildOperations, buildState.GetBuildOperations()); } }
public void Build_Executable() { // Register the test systems var testListener = new TestTraceListener(); using (var scopedTraceListener = new ScopedTraceListenerRegister(testListener)) { // Setup the input build state var buildState = new MockBuildState(); var state = buildState.ActiveState; state.Add("PlatformLibraries", new Value(new ValueList())); state.Add("PlatformIncludePaths", new Value(new ValueList())); state.Add("PlatformLibraryPaths", new Value(new ValueList())); state.Add("PlatformPreprocessorDefinitions", new Value(new ValueList())); // Setup recipe table var buildTable = new ValueTable(); state.Add("Recipe", new Value(buildTable)); buildTable.Add("Name", new Value("Program")); // Setup parameters table var parametersTable = new ValueTable(); state.Add("Parameters", new Value(parametersTable)); parametersTable.Add("TargetDirectory", new Value("C:/Target/")); parametersTable.Add("PackageDirectory", new Value("C:/PackageRoot/")); parametersTable.Add("Compiler", new Value("MOCK")); parametersTable.Add("Flavor", new Value("debug")); var factory = new ValueFactory(); var uut = new RecipeBuildTask(buildState, factory); uut.Execute(); // Verify expected logs Assert.Equal( new List <string>() { }, testListener.GetMessages()); // Verify build state var expectedBuildOperations = new List <BuildOperation>(); Assert.Equal( expectedBuildOperations, buildState.GetBuildOperations()); // TODO: Verify output build state } }
public void Build_Library_MultipleFiles() { // Register the test process manager var processManager = new MockProcessManager(); // Register the test listener var testListener = new TestTraceListener(); using (var scopedTraceListener = new ScopedTraceListenerRegister(testListener)) using (var scopedProcesManager = new ScopedSingleton <IProcessManager>(processManager)) { // Register the mock compiler var compiler = new Mock.Compiler(); // Setup the build arguments var arguments = new BuildArguments(); arguments.TargetName = "Library"; arguments.TargetType = BuildTargetType.Library; arguments.SourceRootDirectory = new Path("C:/source/"); arguments.TargetRootDirectory = new Path("C:/target/"); arguments.ObjectDirectory = new Path("obj/"); arguments.BinaryDirectory = new Path("bin/"); arguments.SourceFiles = new List <Path>() { new Path("TestFile1.cs"), new Path("TestFile2.cs"), new Path("TestFile3.cs"), }; arguments.OptimizationLevel = BuildOptimizationLevel.Size; arguments.LinkDependencies = new List <Path>() { new Path("../Other/bin/OtherModule1.mock.a"), new Path("../OtherModule2.mock.a"), }; arguments.NullableState = BuildNullableState.Disabled; var uut = new BuildEngine(compiler); var fileSystemState = new FileSystemState(); var readAccessList = new List <Path>(); var writeAccessList = new List <Path>(); var buildState = new BuildState(new ValueTable(), fileSystemState, readAccessList, writeAccessList); var result = uut.Execute(buildState, arguments); // Verify expected process manager requests Assert.Equal( new List <string>() { "GetCurrentProcessFileName", "GetCurrentProcessFileName", "GetCurrentProcessFileName", }, processManager.GetRequests()); // Verify expected logs Assert.Equal( new List <string>() { }, testListener.GetMessages()); // Setup the shared arguments var expectedCompileArguments = new CompileArguments() { Target = new Path("./bin/Library.mock.dll"), ReferenceTarget = new Path("./bin/ref/Library.mock.dll"), SourceRootDirectory = new Path("C:/source/"), TargetRootDirectory = new Path("C:/target/"), ObjectDirectory = new Path("obj/"), SourceFiles = new List <Path>() { new Path("TestFile1.cs"), new Path("TestFile2.cs"), new Path("TestFile3.cs"), }, ReferenceLibraries = new List <Path>() { new Path("../Other/bin/OtherModule1.mock.a"), new Path("../OtherModule2.mock.a"), }, NullableState = NullableState.Disabled, }; // Verify expected compiler calls Assert.Equal( new List <CompileArguments>() { expectedCompileArguments, }, compiler.GetCompileRequests()); // Verify build state var expectedBuildOperations = new List <BuildOperation>() { new BuildOperation( "MakeDir [./obj/]", new Path("C:/target/"), new Path("C:/mkdir.exe"), "\"./obj/\"", new List <Path>(), new List <Path>() { new Path("./obj/"), }), new BuildOperation( "MakeDir [./bin/]", new Path("C:/target/"), new Path("C:/mkdir.exe"), "\"./bin/\"", new List <Path>(), new List <Path>() { new Path("./bin/"), }), new BuildOperation( "MakeDir [./bin/ref/]", new Path("C:/target/"), new Path("C:/mkdir.exe"), "\"./bin/ref/\"", new List <Path>(), new List <Path>() { new Path("./bin/ref/"), }), new BuildOperation( "MockCompile: 1", new Path("MockWorkingDirectory"), new Path("MockCompiler.exe"), "Arguments", new List <Path>() { new Path("InputFile.in"), }, new List <Path>() { new Path("OutputFile.out"), }), }; Assert.Equal( expectedBuildOperations, result.BuildOperations); Assert.Equal( new List <Path>() { new Path("C:/target/bin/ref/Library.mock.dll"), }, result.LinkDependencies); Assert.Equal( new List <Path>() { new Path("C:/target/bin/Library.mock.dll"), }, result.RuntimeDependencies); Assert.Equal( new Path("C:/target/bin/Library.mock.dll"), result.TargetFile); } }
public void Build_Executable() { // Register the test process manager var processManager = new MockProcessManager(); // Register the test listener var testListener = new TestTraceListener(); using (var scopedTraceListener = new ScopedTraceListenerRegister(testListener)) using (var scopedProcesManager = new ScopedSingleton <IProcessManager>(processManager)) { // Register the mock compiler var compiler = new Mock.Compiler(); // Setup the build arguments var arguments = new BuildArguments(); arguments.TargetName = "Program"; arguments.TargetType = BuildTargetType.Executable; arguments.SourceRootDirectory = new Path("C:/source/"); arguments.TargetRootDirectory = new Path("C:/target/"); arguments.ObjectDirectory = new Path("obj/"); arguments.BinaryDirectory = new Path("bin/"); arguments.SourceFiles = new List <Path>() { new Path("TestFile.cs"), }; arguments.OptimizationLevel = BuildOptimizationLevel.None; arguments.LinkDependencies = new List <Path>() { new Path("../Other/bin/OtherModule1.mock.a"), new Path("../OtherModule2.mock.a"), }; var uut = new BuildEngine(compiler); var fileSystemState = new FileSystemState(); var readAccessList = new List <Path>(); var writeAccessList = new List <Path>(); var buildState = new BuildState(new ValueTable(), fileSystemState, readAccessList, writeAccessList); var result = uut.Execute(buildState, arguments); // Verify expected process manager requests Assert.Equal( new List <string>() { "GetCurrentProcessFileName", "GetCurrentProcessFileName", "GetCurrentProcessFileName", }, processManager.GetRequests()); // Verify expected logs Assert.Equal( new List <string>() { }, testListener.GetMessages()); var expectedCompileArguments = new CompileArguments() { Target = new Path("./bin/Program.mock.dll"), ReferenceTarget = new Path("./bin/ref/Program.mock.dll"), TargetType = LinkTarget.Executable, ObjectDirectory = new Path("obj/"), SourceRootDirectory = new Path("C:/source/"), TargetRootDirectory = new Path("C:/target/"), SourceFiles = new List <Path>() { new Path("TestFile.cs"), }, ReferenceLibraries = new List <Path>() { new Path("../Other/bin/OtherModule1.mock.a"), new Path("../OtherModule2.mock.a"), }, NullableState = NullableState.Enabled, }; // Verify expected compiler calls var val = compiler.GetCompileRequests()[0]; var areEqual = val == expectedCompileArguments; var areEqual2 = val.ObjectDirectory == expectedCompileArguments.ObjectDirectory; Assert.Equal( new List <CompileArguments>() { expectedCompileArguments, }, compiler.GetCompileRequests()); var expectedBuildOperations = new List <BuildOperation>() { new BuildOperation( "MakeDir [./obj/]", new Path("C:/target/"), new Path("C:/mkdir.exe"), "\"./obj/\"", new List <Path>(), new List <Path>() { new Path("./obj/"), }), new BuildOperation( "MakeDir [./bin/]", new Path("C:/target/"), new Path("C:/mkdir.exe"), "\"./bin/\"", new List <Path>(), new List <Path>() { new Path("./bin/"), }), new BuildOperation( "MakeDir [./bin/ref/]", new Path("C:/target/"), new Path("C:/mkdir.exe"), "\"./bin/ref/\"", new List <Path>(), new List <Path>() { new Path("./bin/ref/"), }), new BuildOperation( "MockCompile: 1", new Path("MockWorkingDirectory"), new Path("MockCompiler.exe"), "Arguments", new List <Path>() { new Path("./InputFile.in"), }, new List <Path>() { new Path("./OutputFile.out"), }), new BuildOperation( "WriteFile [./bin/Program.runtimeconfig.json]", new Path("C:/target/"), new Path("./writefile.exe"), @"""./bin/Program.runtimeconfig.json"" ""{ ""runtimeOptions"": { ""tfm"": ""net5.0"", ""framework"": { ""name"": ""Microsoft.NETCore.App"", ""version"": ""5.0.0"" } } }""", new List <Path>(), new List <Path>() { new Path("./bin/Program.runtimeconfig.json"), }), }; Assert.Equal( expectedBuildOperations, result.BuildOperations); Assert.Equal( new List <Path>(), result.LinkDependencies); Assert.Equal( new List <Path>() { new Path("C:/target/bin/Program.mock.dll"), }, result.RuntimeDependencies); } }
public void Build_Executable() { // Register the test process manager var processManager = new MockProcessManager(); // Register the test listener var testListener = new TestTraceListener(); using (var scopedTraceListener = new ScopedTraceListenerRegister(testListener)) using (var scopedProcesManager = new ScopedSingleton <IProcessManager>(processManager)) { // Setup the input build state var buildState = new MockBuildState(); var state = buildState.ActiveState; // Setup build table var buildTable = new ValueTable(); state.Add("Build", new Value(buildTable)); buildTable.Add("TargetName", new Value("Program")); buildTable.Add("TargetType", new Value((long)BuildTargetType.Executable)); buildTable.Add("SourceRootDirectory", new Value("C:/source/")); buildTable.Add("TargetRootDirectory", new Value("C:/target/")); buildTable.Add("ObjectDirectory", new Value("obj/")); buildTable.Add("BinaryDirectory", new Value("bin/")); buildTable.Add( "Source", new Value(new ValueList() { new Value("TestFile.cs"), })); // Setup parameters table var parametersTable = new ValueTable(); state.Add("Parameters", new Value(parametersTable)); parametersTable.Add("Architecture", new Value("x64")); parametersTable.Add("Compiler", new Value("MOCK")); // Register the mock compiler var compiler = new Compiler.Mock.Compiler(); var compilerFactory = new Dictionary <string, Func <IValueTable, ICompiler> >(); compilerFactory.Add("MOCK", (IValueTable state) => { return(compiler); }); var factory = new ValueFactory(); var uut = new BuildTask(buildState, factory, compilerFactory); uut.Execute(); // Verify expected process manager requests Assert.Equal( new List <string>() { "GetCurrentProcessFileName", "GetCurrentProcessFileName", "GetCurrentProcessFileName", }, processManager.GetRequests()); // Verify expected logs Assert.Equal( new List <string>() { "INFO: Build Generate Done" }, testListener.GetMessages()); var expectedCompileArguments = new CompileArguments() { Target = new Path("./bin/Program.mock.dll"), ReferenceTarget = new Path("./bin/ref/Program.mock.dll"), TargetType = LinkTarget.Executable, SourceRootDirectory = new Path("C:/source/"), TargetRootDirectory = new Path("C:/target/"), ObjectDirectory = new Path("obj/"), SourceFiles = new List <Path>() { new Path("TestFile.cs") }, }; // Verify expected compiler calls Assert.Equal( new List <CompileArguments>() { expectedCompileArguments, }, compiler.GetCompileRequests()); // Verify build state var expectedBuildOperations = new List <BuildOperation>() { new BuildOperation( "MakeDir [./obj/]", new Path("C:/target/"), new Path("C:/mkdir.exe"), "\"./obj/\"", new List <Path>(), new List <Path>() { new Path("./obj/"), }), new BuildOperation( "MakeDir [./bin/]", new Path("C:/target/"), new Path("C:/mkdir.exe"), "\"./bin/\"", new List <Path>(), new List <Path>() { new Path("./bin/"), }), new BuildOperation( "MakeDir [./bin/ref/]", new Path("C:/target/"), new Path("C:/mkdir.exe"), "\"./bin/ref/\"", new List <Path>(), new List <Path>() { new Path("./bin/ref/"), }), new BuildOperation( "MockCompile: 1", new Path("MockWorkingDirectory"), new Path("MockCompiler.exe"), "Arguments", new List <Path>() { new Path("./InputFile.in"), }, new List <Path>() { new Path("./OutputFile.out"), }), new BuildOperation( "WriteFile [./bin/Program.runtimeconfig.json]", new Path("C:/target/"), new Path("./writefile.exe"), @"""./bin/Program.runtimeconfig.json"" ""{ ""runtimeOptions"": { ""tfm"": ""net5.0"", ""framework"": { ""name"": ""Microsoft.NETCore.App"", ""version"": ""5.0.0"" } } }""", new List <Path>(), new List <Path>() { new Path("./bin/Program.runtimeconfig.json"), }), }; Assert.Equal( expectedBuildOperations, buildState.GetBuildOperations()); } }
public void Build_Library_MultipleFiles() { // Register the test process manager var processManager = new MockProcessManager(); // Register the test listener var testListener = new TestTraceListener(); using (var scopedTraceListener = new ScopedTraceListenerRegister(testListener)) using (var scopedProcesManager = new ScopedSingleton <IProcessManager>(processManager)) { // Setup the input build state var buildState = new MockBuildState(); var state = buildState.ActiveState; // Setup build table var buildTable = new ValueTable(); state.Add("Build", new Value(buildTable)); buildTable.Add("TargetName", new Value("Library")); buildTable.Add("TargetType", new Value((long)BuildTargetType.Library)); buildTable.Add("SourceRootDirectory", new Value("C:/source/")); buildTable.Add("TargetRootDirectory", new Value("C:/target/")); buildTable.Add("ObjectDirectory", new Value("obj/")); buildTable.Add("BinaryDirectory", new Value("bin/")); buildTable.Add("Source", new Value(new ValueList() { new Value("TestFile1.cpp"), new Value("TestFile2.cpp"), new Value("TestFile3.cpp"), })); buildTable.Add("IncludeDirectories", new Value(new ValueList() { new Value("Folder"), new Value("AnotherFolder/Sub"), })); buildTable.Add("ModuleDependencies", new Value(new ValueList() { new Value("../Other/bin/OtherModule1.mock.bmi"), new Value("../OtherModule2.mock.bmi"), })); buildTable.Add("OptimizationLevel", new Value((long)BuildOptimizationLevel.None)); // Setup parameters table var parametersTable = new ValueTable(); state.Add("Parameters", new Value(parametersTable)); parametersTable.Add("Architecture", new Value("x64")); parametersTable.Add("Compiler", new Value("MOCK")); // Register the mock compiler var compiler = new Compiler.Mock.Compiler(); var compilerFactory = new Dictionary <string, Func <IValueTable, ICompiler> >(); compilerFactory.Add("MOCK", (IValueTable state) => { return(compiler); }); var factory = new ValueFactory(); var uut = new BuildTask(buildState, factory, compilerFactory); uut.Execute(); // Verify expected process manager requests Assert.Equal( new List <string>() { "GetCurrentProcessFileName", "GetCurrentProcessFileName", "GetCurrentProcessFileName", }, processManager.GetRequests()); // Verify expected logs Assert.Equal( new List <string>() { "INFO: Build Generate Done", }, testListener.GetMessages()); // Setup the shared arguments var expectedCompileArguments = new CompileArguments() { Target = new Path("./bin/Library.mock.dll"), ReferenceTarget = new Path("./bin/ref/Library.mock.dll"), SourceRootDirectory = new Path("C:/source/"), TargetRootDirectory = new Path("C:/target/"), ObjectDirectory = new Path("obj/"), SourceFiles = new List <Path>() { new Path("TestFile1.cpp"), new Path("TestFile2.cpp"), new Path("TestFile3.cpp"), }, }; // Verify expected compiler calls Assert.Equal( new List <CompileArguments>() { expectedCompileArguments, }, compiler.GetCompileRequests()); // Verify build state var expectedBuildOperations = new List <BuildOperation>() { new BuildOperation( "MakeDir [./obj/]", new Path("C:/target/"), new Path("C:/mkdir.exe"), "\"./obj/\"", new List <Path>(), new List <Path>() { new Path("./obj/"), }), new BuildOperation( "MakeDir [./bin/]", new Path("C:/target/"), new Path("C:/mkdir.exe"), "\"./bin/\"", new List <Path>(), new List <Path>() { new Path("./bin/"), }), new BuildOperation( "MakeDir [./bin/ref/]", new Path("C:/target/"), new Path("C:/mkdir.exe"), "\"./bin/ref/\"", new List <Path>(), new List <Path>() { new Path("./bin/ref/"), }), new BuildOperation( "MockCompile: 1", new Path("MockWorkingDirectory"), new Path("MockCompiler.exe"), "Arguments", new List <Path>() { new Path("./InputFile.in"), }, new List <Path>() { new Path("./OutputFile.out"), }), }; Assert.Equal( expectedBuildOperations, buildState.GetBuildOperations()); } }
public void BuildGraph_DependencyNodes_FlattenGraph() { // Register the test listener var testListener = new TestTraceListener(); using var scopedTraceListener = new ScopedTraceListenerRegister(testListener); var fileSystemState = new FileSystemState(); var readAccessList = new List <Path>() { new Path("C:/WorkingDir/ReadAccess/"), new Path("C:/WorkingDir/WriteAccess/"), }; var writeAccessList = new List <Path>() { new Path("C:/WorkingDir/WriteAccess/"), }; var uut = new OperationGraphGenerator(fileSystemState, readAccessList, writeAccessList); uut.CreateOperation( "Do Stuff 1", new Path("DoStuff.exe"), "do stuff 1", new Path("C:/WorkingDir/"), new List <Path>() { new Path("./ReadAccess/ReadFile.txt"), }, new List <Path>() { new Path("./WriteAccess/WriteFile1.txt"), }); uut.CreateOperation( "Do Stuff 2", new Path("DoStuff.exe"), "do stuff 2", new Path("C:/WorkingDir/"), new List <Path>() { new Path("./WriteAccess/WriteFile1.txt"), }, new List <Path>() { new Path("./WriteAccess/WriteFile2.txt"), }); // Create a third operation that reads the output of the other two // The graph builder should flatten these references to be dependent on the single second node that already // is dependent on the first node. uut.CreateOperation( "Do Stuff 3", new Path("DoStuff.exe"), "do stuff 3", new Path("C:/WorkingDir/"), new List <Path>() { new Path("./WriteAccess/WriteFile1.txt"), new Path("./WriteAccess/WriteFile2.txt"), }, new List <Path>() { new Path("./WriteAccess/WriteFile3.txt"), }); var graph = uut.BuildGraph(); // Verify expected logs Assert.Equal( new List <string>() { "DIAG: Create Operation: Do Stuff 1", "DIAG: Read Access Subset:", "DIAG: C:/WorkingDir/ReadAccess/", "DIAG: Write Access Subset:", "DIAG: C:/WorkingDir/WriteAccess/", "DIAG: Create Operation: Do Stuff 2", "DIAG: Read Access Subset:", "DIAG: C:/WorkingDir/WriteAccess/", "DIAG: Write Access Subset:", "DIAG: C:/WorkingDir/WriteAccess/", "DIAG: Create Operation: Do Stuff 3", "DIAG: Read Access Subset:", "DIAG: C:/WorkingDir/WriteAccess/", "DIAG: Write Access Subset:", "DIAG: C:/WorkingDir/WriteAccess/", }, testListener.GetMessages()); Assert.Equal( new Dictionary <OperationId, OperationInfo>() { { new OperationId(1), new OperationInfo() { Id = new OperationId(1), Title = "Do Stuff 1", Command = new CommandInfo() { Executable = new Path("DoStuff.exe"), Arguments = "do stuff 1", WorkingDirectory = new Path("C:/WorkingDir/"), }, DeclaredInput = new List <FileId>() { new FileId(1), }, DeclaredOutput = new List <FileId>() { new FileId(2), }, ReadAccess = new List <FileId>() { new FileId(3), }, WriteAccess = new List <FileId>() { new FileId(4), }, DependencyCount = 1, Children = new List <OperationId>() { new OperationId(2), }, } }, { new OperationId(2), new OperationInfo() { Id = new OperationId(2), Title = "Do Stuff 2", Command = new CommandInfo() { Executable = new Path("DoStuff.exe"), Arguments = "do stuff 2", WorkingDirectory = new Path("C:/WorkingDir/"), }, DeclaredInput = new List <FileId>() { new FileId(2), }, DeclaredOutput = new List <FileId>() { new FileId(5), }, ReadAccess = new List <FileId>() { new FileId(4), }, WriteAccess = new List <FileId>() { new FileId(4), }, DependencyCount = 1, Children = new List <OperationId>() { new OperationId(3), }, } }, { new OperationId(3), new OperationInfo() { Id = new OperationId(3), Title = "Do Stuff 3", Command = new CommandInfo() { Executable = new Path("DoStuff.exe"), Arguments = "do stuff 3", WorkingDirectory = new Path("C:/WorkingDir/"), }, DeclaredInput = new List <FileId>() { new FileId(2), new FileId(5), }, DeclaredOutput = new List <FileId>() { new FileId(6), }, ReadAccess = new List <FileId>() { new FileId(4), }, WriteAccess = new List <FileId>() { new FileId(4), }, DependencyCount = 1, } }, }, graph.GetOperations()); Assert.Equal( new List <OperationId>() { new OperationId(1), }, graph.GetRootOperationIds()); Assert.Equal( new List <(FileId, Path)>(), graph.GetReferencedFiles()); }
public void BuildGraph_SingleNodes() { // Register the test listener var testListener = new TestTraceListener(); using var scopedTraceListener = new ScopedTraceListenerRegister(testListener); var fileSystemState = new FileSystemState(); var readAccessList = new List <Path>() { new Path("C:/WorkingDir/ReadAccess/") }; var writeAccessList = new List <Path>() { new Path("C:/WorkingDir/WriteAccess/") }; var uut = new OperationGraphGenerator(fileSystemState, readAccessList, writeAccessList); uut.CreateOperation( "Do Stuff", new Path("DoStuff.exe"), "do stuff", new Path("C:/WorkingDir/"), new List <Path>() { new Path("./ReadAccess/ReadFile.txt"), }, new List <Path>() { new Path("./WriteAccess/WriteFile.txt"), }); var graph = uut.BuildGraph(); // Verify expected logs Assert.Equal( new List <string>() { "DIAG: Create Operation: Do Stuff", "DIAG: Read Access Subset:", "DIAG: C:/WorkingDir/ReadAccess/", "DIAG: Write Access Subset:", "DIAG: C:/WorkingDir/WriteAccess/", }, testListener.GetMessages()); Assert.Equal( new Dictionary <OperationId, OperationInfo>() { { new OperationId(1), new OperationInfo() { Id = new OperationId(1), Title = "Do Stuff", Command = new CommandInfo() { Executable = new Path("DoStuff.exe"), Arguments = "do stuff", WorkingDirectory = new Path("C:/WorkingDir/"), }, DeclaredInput = new List <FileId>() { new FileId(1), }, DeclaredOutput = new List <FileId>() { new FileId(2), }, ReadAccess = new List <FileId>() { new FileId(3), }, WriteAccess = new List <FileId>() { new FileId(4), }, DependencyCount = 1, } }, }, graph.GetOperations()); Assert.Equal( new List <OperationId>() { new OperationId(1), }, graph.GetRootOperationIds()); Assert.Equal( new List <(FileId, Path)>(), graph.GetReferencedFiles()); }