-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Qtest
library that uses class constraints
#2013
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"author": "Microsoft", | ||
"license": "MIT", | ||
"files": [ | ||
"src/Functions.qs", | ||
"src/Main.qs", | ||
"src/Operations.qs", | ||
"src/Tests.qs", | ||
"src/Util.qs" | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
import Util.TestCaseResult, Util.OutputMessage; | ||
import Std.Arrays.Mapped, Std.Arrays.All; | ||
|
||
/// # Summary | ||
/// Runs a number of test cases and returns true if all tests passed, false otherwise. | ||
/// Prints a report of what passed and what failed as output. | ||
/// | ||
/// For a more flexible test running function, see `RunAllTestCases` which returns | ||
/// test results instead of printing out to output. | ||
/// | ||
/// # Input | ||
/// Takes a list of test cases. A test case is a tuple of `(String, () -> T, 'T)`, where | ||
/// the first String is the name of the test, the function is the test case itself, and the | ||
/// final element of the tuple is the expected return value from the test case. | ||
/// | ||
/// # Example | ||
/// ```qsharp | ||
/// CheckAllTestCases([("Should return 42", () -> 42, 42)]); | ||
/// ``` | ||
function CheckAllTestCases<'T : Eq + Show>(test_cases : (String, () -> 'T, 'T)[]) : Bool { | ||
let test_results = RunAllTestCases(test_cases); | ||
|
||
OutputMessage(test_results); | ||
All(test_case -> test_case.did_pass, test_results) | ||
} | ||
|
||
/// # Summary | ||
/// Runs all given test cases and returns a `TestCaseResult` for each test, representing whether or not it passed | ||
/// and what the failure message, if any. | ||
/// This is a good alternative to `CheckAllTestCases` when you want custom output based on the results of your tests, | ||
/// or more control over how test results are rendered. | ||
/// # Input | ||
/// Takes a list of test cases. A test case is a tuple of `(String, () -> T, 'T)`, where | ||
/// the first String is the name of the test, the function is the test case itself, and the | ||
/// final element of the tuple is the expected return value from the test case. | ||
/// | ||
/// # Example | ||
/// ```qsharp | ||
/// RunAllTestCases([("Should return 42", () -> 42, 42)]); | ||
/// ``` | ||
function RunAllTestCases<'T : Eq + Show>(test_cases : (String, () -> 'T, 'T)[]) : TestCaseResult[] { | ||
let num_tests = Length(test_cases); | ||
|
||
Mapped((name, case, result) -> TestCase(name, case, result), test_cases) | ||
} | ||
|
||
/// Internal (non-exported) helper function. Runs a test case and produces a `TestCaseResult` | ||
function TestCase<'T : Eq + Show>(name : String, test_case : () -> 'T, expected : 'T) : TestCaseResult { | ||
let result = test_case(); | ||
if result == expected { | ||
new TestCaseResult { did_pass = true, message = "" } | ||
} else { | ||
new TestCaseResult { did_pass = false, message = $"{name}: expected: {expected}, got: {result}" } | ||
} | ||
} | ||
|
||
export CheckAllTestCases, RunAllTestCases; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
export Util.TestCaseResult; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
import Util.TestCaseResult, Util.OutputMessage; | ||
import Std.Arrays.Mapped, Std.Arrays.All; | ||
|
||
/// # Summary | ||
/// Runs a number of test cases and returns true if all tests passed, false otherwise. | ||
/// Prints a report of what passed and what failed as output. | ||
/// | ||
/// For a more flexible test running function, see `RunAllTestCases` which returns | ||
/// test results instead of printing out to output. | ||
/// | ||
/// # Input | ||
/// Takes a list of test cases. A test case is a tuple of `(String, () -> T, 'T)`, where | ||
/// the first String is the name of the test, the function is the test case itself, and the | ||
/// final element of the tuple is the expected return value from the test case. | ||
/// | ||
/// # Example | ||
sezna marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// ```qsharp | ||
/// CheckAllTestCases([("Should return 42", () -> 42, 42)]); | ||
/// ``` | ||
operation CheckAllTestCases<'T : Eq + Show>(test_cases : (String, Int, (Qubit[]) => (), (Qubit[]) => 'T, 'T)[]) : Bool { | ||
let test_results = RunAllTestCases(test_cases); | ||
|
||
OutputMessage(test_results); | ||
|
||
All(test_case -> test_case.did_pass, test_results) | ||
|
||
} | ||
|
||
/// # Summary | ||
/// Runs all given test cases and returns a `TestCaseResult` for each test, representing whether or not it passed | ||
/// and what the failure message, if any. | ||
/// This is a good alternative to `CheckAllTestCases` when you want custom output based on the results of your tests, | ||
/// or more control over how test results are rendered. | ||
/// # Input | ||
/// Takes a list of test cases. A test case is a tuple of `(String, () -> T, 'T)`, where | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Similarly here. |
||
/// the first String is the name of the test, the function is the test case itself, and the | ||
/// final element of the tuple is the expected return value from the test case. | ||
/// | ||
/// # Example | ||
/// ```qsharp | ||
/// RunAllTestCases([("Should return 42", () -> 42, 42)]); | ||
/// ``` | ||
operation RunAllTestCases<'T : Eq + Show>(test_cases : (String, Int, (Qubit[]) => (), (Qubit[]) => 'T, 'T)[]) : TestCaseResult[] { | ||
let num_tests = Length(test_cases); | ||
|
||
let num_tests = Length(test_cases); | ||
|
||
MappedOperation((name, num_qubits, prepare_state, case, result) => { | ||
use qubits = Qubit[num_qubits]; | ||
prepare_state(qubits); | ||
let res = TestCase(name, qubits, case, result); | ||
ResetAll(qubits); | ||
res | ||
}, test_cases) | ||
} | ||
|
||
/// Helper function, copy of `Std.Arrays.Mapped` which works on operations instead | ||
/// of functions. | ||
operation MappedOperation<'T, 'U>(mapper : ('T => 'U), array : 'T[]) : 'U[] { | ||
mutable mapped = []; | ||
for element in array { | ||
set mapped += [mapper(element)]; | ||
} | ||
mapped | ||
} | ||
|
||
/// Internal (non-exported) helper function. Runs a test case and produces a `TestCaseResult` | ||
operation TestCase<'T : Eq + Show>(name : String, qubits : Qubit[], test_case : (Qubit[]) => 'T, expected : 'T) : TestCaseResult { | ||
let result = test_case(qubits); | ||
if result == expected { | ||
new TestCaseResult { did_pass = true, message = "" } | ||
} else { | ||
new TestCaseResult { did_pass = false, message = $"{name}: expected: {expected}, got: {result}" } | ||
} | ||
} | ||
|
||
export CheckAllTestCases, RunAllTestCases; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
import Std.Diagnostics.Fact; | ||
|
||
function Main() : Unit { | ||
let sample_tests = [ | ||
("Should return 42", TestCaseOne, 43), | ||
("Should add one", () -> AddOne(5), 42), | ||
("Should add one", () -> AddOne(5), 6) | ||
]; | ||
|
||
Fact( | ||
not Functions.CheckAllTestCases(sample_tests), | ||
"Test harness failed to return false for a failing tests." | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: for a failing test/for the failing test(s). |
||
); | ||
|
||
Fact( | ||
Functions.CheckAllTestCases([("always returns true", () -> true, true)]), | ||
"Test harness failed to return true for a passing test" | ||
); | ||
|
||
let run_all_result = Functions.RunAllTestCases(sample_tests); | ||
|
||
Fact( | ||
Length(run_all_result) == 3, | ||
"Test harness did not return results for all test cases." | ||
); | ||
sezna marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Fact(run_all_result[0].did_pass, "test one passed when it should have failed"); | ||
Fact(run_all_result[1].did_pass, "test two failed when it should have passed"); | ||
Fact(run_all_result[2].did_pass, "test three passed when it should have failed"); | ||
} | ||
|
||
function TestCaseOne() : Int { | ||
42 | ||
} | ||
|
||
function AddOne(x : Int) : Int { | ||
x + 1 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
import Std.Arrays.Filtered; | ||
import Std.Diagnostics.Fact; | ||
|
||
struct TestCaseResult { | ||
did_pass : Bool, | ||
message : String, | ||
} | ||
|
||
|
||
function OutputMessage(test_results : TestCaseResult[]) : Unit { | ||
let num_tests = Length(test_results); | ||
let failed_tests = Filtered((item -> not item.did_pass), test_results); | ||
let num_passed = Std.Arrays.Count((item -> item.did_pass), test_results); | ||
let num_failed = Length(failed_tests); | ||
|
||
Fact((num_passed + num_failed) == num_tests, "invariant failed in test harness: passed plus failed should equal total"); | ||
|
||
let test_word = if num_tests == 1 or num_tests == 0 { "test" } else { "tests" }; | ||
Message($"{num_passed} of {num_tests} {test_word} passed. ({num_failed} failed)"); | ||
for failed_test in failed_tests { | ||
Message($"{failed_test.message}"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,47 +8,24 @@ import Measurement.MeasureSignedInteger; | |
/// This entrypoint runs tests for the signed integer library. | ||
operation Main() : Unit { | ||
UnsignedOpTests(); | ||
MeasureSignedIntTests(); | ||
Fact(Qtest.Operations.CheckAllTestCases(MeasureSignedIntTests()), "SignedInt tests failed"); | ||
SignedOpTests(); | ||
sezna marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
} | ||
|
||
operation MeasureSignedIntTests() : Unit { | ||
use a = Qubit[4]; | ||
|
||
// 0b0001 == 1 | ||
X(a[0]); | ||
let res = MeasureSignedInteger(a, 4); | ||
Fact(res == 1, $"Expected 1, received {res}"); | ||
|
||
// 0b1111 == -1 | ||
X(a[0]); | ||
X(a[1]); | ||
X(a[2]); | ||
X(a[3]); | ||
let res = MeasureSignedInteger(a, 4); | ||
Fact(res == -1, $"Expected -1, received {res}"); | ||
|
||
// 0b01000 == 8 | ||
use a = Qubit[5]; | ||
X(a[3]); | ||
let res = MeasureSignedInteger(a, 5); | ||
Fact(res == 8, $"Expected 8, received {res}"); | ||
|
||
// 0b11110 == -2 | ||
X(a[1]); | ||
X(a[2]); | ||
X(a[3]); | ||
X(a[4]); | ||
let res = MeasureSignedInteger(a, 5); | ||
Fact(res == -2, $"Expected -2, received {res}"); | ||
|
||
// 0b11000 == -8 | ||
X(a[3]); | ||
X(a[4]); | ||
let res = MeasureSignedInteger(a, 5); | ||
Fact(res == -8, $"Expected -8, received {res}"); | ||
|
||
function MeasureSignedIntTests() : (String, Int, (Qubit[]) => (), (Qubit[]) => Int, Int)[] { | ||
sezna marked this conversation as resolved.
Show resolved
Hide resolved
|
||
[ | ||
("0b0001 == 1", 4, (qs) => X(qs[0]), (qs) => MeasureSignedInteger(qs, 4), 1), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sezna , it seems these tests should not pass since the signature of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey Manvi, I'm not seeing an issue here. The function call here does indeed use the latest api. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sezna, I realized it now, that this still accepts a tuple containing 5 values. I think I got confused by 2 factors:
|
||
("0b1111 == -1", 4, (qs) => { X(qs[0]); X(qs[1]); X(qs[2]); X(qs[3]); }, (qs) => MeasureSignedInteger(qs, 4), -1), | ||
("0b01000 == 8", 5, (qs) => X(qs[3]), (qs) => MeasureSignedInteger(qs, 5), 8), | ||
("0b11110 == -2", 5, (qs) => { | ||
X(qs[1]); | ||
X(qs[2]); | ||
X(qs[3]); | ||
X(qs[4]); | ||
}, (qs) => MeasureSignedInteger(qs, 5), -2), | ||
("0b11000 == -8", 5, (qs) => { X(qs[3]); X(qs[4]); }, (qs) => MeasureSignedInteger(qs, 5), -8) | ||
] | ||
} | ||
|
||
operation SignedOpTests() : Unit { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
(String, () => T, 'T)