diff --git a/Simulation.sln b/Simulation.sln index da0f6964563..4ba93680295 100644 --- a/Simulation.sln +++ b/Simulation.sln @@ -103,6 +103,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "qir-gen", "src\Qir\Runtime\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tracer-qir", "src\Qir\Runtime\test\QIR-tracer\qsharp\tracer-qir.csproj", "{5917D4C5-0CD2-4BD1-A859-19B9B97FF8A7}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "controller", "controller", "{A25E062D-C685-48DE-99D1-B5BC0DF73F89}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QirController", "src\Qir\Controller\QirController.csproj", "{55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -739,6 +743,22 @@ Global {5917D4C5-0CD2-4BD1-A859-19B9B97FF8A7}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {5917D4C5-0CD2-4BD1-A859-19B9B97FF8A7}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {5917D4C5-0CD2-4BD1-A859-19B9B97FF8A7}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.Debug|x64.ActiveCfg = Debug|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.Debug|x64.Build.0 = Debug|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.Release|Any CPU.Build.0 = Release|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.Release|x64.ActiveCfg = Release|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.Release|x64.Build.0 = Release|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3}.RelWithDebInfo|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -787,6 +807,8 @@ Global {9DF6FEB7-3111-4244-B4EE-A69C64043967} = {3FFDEA49-C6E8-45BB-BCA5-BBC5378F704F} {241693D7-4AA6-47C9-9F27-78F2A1EE0904} = {3FFDEA49-C6E8-45BB-BCA5-BBC5378F704F} {5917D4C5-0CD2-4BD1-A859-19B9B97FF8A7} = {3FFDEA49-C6E8-45BB-BCA5-BBC5378F704F} + {A25E062D-C685-48DE-99D1-B5BC0DF73F89} = {C637C9DF-14AA-48CB-95F3-73CE0AC5F9B1} + {55AC2357-5C70-4CAC-9A1F-4146E2D81CE3} = {A25E062D-C685-48DE-99D1-B5BC0DF73F89} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {929C0464-86D8-4F70-8835-0A5EAF930821} diff --git a/build/test.ps1 b/build/test.ps1 index b80d5ab936f..c4d9e732bf3 100644 --- a/build/test.ps1 +++ b/build/test.ps1 @@ -43,6 +43,12 @@ if ($Env:ENABLE_QIRRUNTIME -ne "false") { if ($LastExitCode -ne 0) { $script:all_ok = $False } + + $qirController = (Join-Path $PSScriptRoot "../src/Qir/Controller") + & "$qirController/test-qir-controller.ps1" + if ($LastExitCode -ne 0) { + $script:all_ok = $False + } } else { Write-Host "Skipping test of qir runtime because ENABLE_QIRRUNTIME variable is set to: $Env:ENABLE_QIRRUNTIME ` and ENABLE_NATIVE variable is set to: $Env:ENABLE_NATIVE." diff --git a/src/Qir/Controller/Controller.cs b/src/Qir/Controller/Controller.cs new file mode 100644 index 00000000000..0f613d5fc0c --- /dev/null +++ b/src/Qir/Controller/Controller.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.IO; +using System.Text; + +namespace Microsoft.Quantum.Qir +{ + internal static class Controller + { + internal static void Execute( + FileInfo input, + FileInfo output, + FileInfo error) + { + var outputFileStream = output.Exists ? output.OpenWrite() : output.Create(); + outputFileStream.Write(new UTF8Encoding().GetBytes("output")); + outputFileStream.Flush(); + outputFileStream.Close(); + var errorFileStream = error.Exists ? error.OpenWrite() : error.Create(); + errorFileStream.Write(new UTF8Encoding().GetBytes("error")); + errorFileStream.Flush(); + errorFileStream.Close(); + } + } +} diff --git a/src/Qir/Controller/Program.cs b/src/Qir/Controller/Program.cs new file mode 100644 index 00000000000..e7fec1e6fd0 --- /dev/null +++ b/src/Qir/Controller/Program.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.CommandLine; +using System.CommandLine.Invocation; +using System.IO; + +namespace Microsoft.Quantum.Qir +{ + class Program + { + static void Main(string[] args) + { + var rootCommand = new RootCommand( + description: "Builds and runs QIR executable."); + + // Create and add options to the root command. + var inputOption = new Option( + aliases: new string[] { "--input"}) + { + Description = "Path to the file that contains the input.", + IsRequired = true + }; + + rootCommand.AddOption(inputOption); + var outputOption = new Option( + aliases: new string[] { "--output"}) + { + Description = "Path to the file to which the output will be written.", + IsRequired = true + }; + + rootCommand.AddOption(outputOption); + var errorOption = new Option( + aliases: new string[] { "--error",}) + { + Description = "Path to the file to which errors will be logged.", + IsRequired = true + }; + + rootCommand.AddOption(errorOption); + + // Bind to a handler and invoke. + rootCommand.Handler = CommandHandler.Create((input, output, error) => Controller.Execute(input, output, error)); + rootCommand.Invoke(args); + } + } +} diff --git a/src/Qir/Controller/QirController.csproj b/src/Qir/Controller/QirController.csproj new file mode 100644 index 00000000000..0c21b5914f9 --- /dev/null +++ b/src/Qir/Controller/QirController.csproj @@ -0,0 +1,12 @@ + + + + Exe + netcoreapp3.1 + + + + + + + diff --git a/src/Qir/Controller/test-cases/01.err b/src/Qir/Controller/test-cases/01.err new file mode 100644 index 00000000000..760589cb5d6 --- /dev/null +++ b/src/Qir/Controller/test-cases/01.err @@ -0,0 +1 @@ +error \ No newline at end of file diff --git a/src/Qir/Controller/test-cases/01.in b/src/Qir/Controller/test-cases/01.in new file mode 100644 index 00000000000..770eab4480b --- /dev/null +++ b/src/Qir/Controller/test-cases/01.in @@ -0,0 +1 @@ +input \ No newline at end of file diff --git a/src/Qir/Controller/test-cases/01.out b/src/Qir/Controller/test-cases/01.out new file mode 100644 index 00000000000..6caf68aff42 --- /dev/null +++ b/src/Qir/Controller/test-cases/01.out @@ -0,0 +1 @@ +output \ No newline at end of file diff --git a/src/Qir/Controller/test-qir-controller.ps1 b/src/Qir/Controller/test-qir-controller.ps1 new file mode 100644 index 00000000000..876626b703a --- /dev/null +++ b/src/Qir/Controller/test-qir-controller.ps1 @@ -0,0 +1,56 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +$all_ok = $True + +Write-Host "##[info]Test QIR Controller" + +$controllerProject = (Join-Path $PSScriptRoot QirController.csproj) +$testCasesFolder = (Join-Path $PSScriptRoot "test-cases") +$testArtifactsFolder = (Join-Path $PSScriptRoot "test-artifacts") +if (!(Test-Path $testArtifactsFolder -PathType Container)) { + New-Item -ItemType Directory -Force -Path $testArtifactsFolder +} +Get-ChildItem -Path $testArtifactsFolder | Remove-Item -Force + +# Go through each input file in the test cases folder. +Get-ChildItem $testCasesFolder -Filter *.in | +Foreach-Object { + # Get the paths to the output and error files to pass to the QIR controller. + $outputFile = (Join-Path $testArtifactsFolder ($_.BaseName + ".out")) + $errorFile = (Join-Path $testArtifactsFolder ($_.BaseName + ".err")) + dotnet run --project $controllerProject -- --input $_.FullName --output $outputFile --error $errorFile + + # Compare the expected content of the output and error files vs the actual content. + $expectedOutputFile = (Join-Path $testCasesFolder ($_.BaseName + ".out")) + $expectedOutput = Get-Content -Path $expectedOutputFile -Raw + $actualOutput = Get-Content -Path $outputFile -Raw + if (-not ($expectedOutput -ceq $actualOutput)) { + Write-Host "##vso[task.logissue type=error;]Failed QIR Controller test case: $($_.BaseName)" + Write-Host "##[info]Expected output:" + Write-Host $expectedOutput + Write-Host "##[info]Actual output:" + Write-Host $actualOutput + $script:all_ok = $False + break + } + + $expectedErrorFile = (Join-Path $testCasesFolder ($_.BaseName + ".err")) + $expectedError = Get-Content -Path $expectedErrorFile -Raw + $actualError = Get-Content -Path $errorFile -Raw + if (-not ($expectedError -ceq $actualError)) { + Write-Host "##vso[task.logissue type=error;]Failed QIR Controller test case: $($_.BaseName)" + Write-Host "##[info]Expected error:" + Write-Host $expectedError + Write-Host "##[info]Actual error:" + Write-Host $actualError + $script:all_ok = $False + break + } + + Write-Host "##[info]Test case '$($_.BaseName)' passed" +} + +if (-not $all_ok) { + throw "At least one project failed testing. Check the logs." +}