From 4b326b449a4c171fc0a7f28bcd272e869ded23ba Mon Sep 17 00:00:00 2001 From: Damian Rovara <93778306+DRovara@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:06:06 +0200 Subject: [PATCH] test: :white_check_mark: Add and update tests to increase coverage (#18) * test: :white_check_mark: Add and update tests to increase coverage * fix: :bug: Fix incorrect test * style: :recycle: Fix linter issues * test: :white_check_mark: Add test for situation where user requests 0 problem causes from diagnostics --- src/backend/dd/DDSimDebug.cpp | 14 ++- src/backend/dd/DDSimDiagnostics.cpp | 8 ++ src/common/parsing/AssertionParsing.cpp | 5 +- src/common/parsing/CodePreprocessing.cpp | 3 +- .../failing-assertions-multiple-causes.qasm | 6 ++ ...sertions-multiple-missing-interaction.qasm | 5 + ...ing-assertions-multiple-zero-controls.qasm | 7 ++ test/test_custom_code.cpp | 90 +++++++++++++++- test/test_data_retrieval.cpp | 13 +++ test/test_diagnostics.cpp | 78 ++++++++++++++ test/test_parsing.cpp | 42 ++++++++ test/test_simulation.cpp | 102 +++++++++++++++++- test/test_utility.cpp | 9 ++ 13 files changed, 369 insertions(+), 13 deletions(-) create mode 100644 test/circuits/failing-assertions-multiple-causes.qasm create mode 100644 test/circuits/failing-assertions-multiple-missing-interaction.qasm create mode 100644 test/circuits/failing-assertions-multiple-zero-controls.qasm diff --git a/src/backend/dd/DDSimDebug.cpp b/src/backend/dd/DDSimDebug.cpp index c5e9121..729e9a8 100644 --- a/src/backend/dd/DDSimDebug.cpp +++ b/src/backend/dd/DDSimDebug.cpp @@ -250,9 +250,6 @@ Result ddsimStepOutBackward(SimulationState* self) { const auto size = ddsim->callReturnStack.size(); Result res = OK; while ((res = self->stepBackward(self)) == OK) { - if (self->wasBreakpointHit(self)) { - break; - } if (self->wasBreakpointHit(self)) { break; } @@ -513,6 +510,9 @@ Result ddsimRunAll(SimulationState* self, size_t* failedAssertions) { Result ddsimRunSimulation(SimulationState* self) { auto* ddsim = toDDSimulationState(self); + if (!self->canStepForward(self)) { + return ERROR; + } while (!self->isFinished(self)) { if (ddsim->paused) { ddsim->paused = false; @@ -531,6 +531,9 @@ Result ddsimRunSimulation(SimulationState* self) { Result ddsimRunSimulationBackward(SimulationState* self) { auto* ddsim = toDDSimulationState(self); + if (!self->canStepBackward(self)) { + return ERROR; + } while (self->canStepBackward(self)) { if (ddsim->paused) { ddsim->paused = false; @@ -570,12 +573,13 @@ Result ddsimPauseSimulation(SimulationState* self) { bool ddsimCanStepForward(SimulationState* self) { auto* ddsim = toDDSimulationState(self); - return ddsim->currentInstruction < ddsim->instructionTypes.size(); + return ddsim->ready && + ddsim->currentInstruction < ddsim->instructionTypes.size(); } bool ddsimCanStepBackward(SimulationState* self) { auto* ddsim = toDDSimulationState(self); - return !ddsim->previousInstructionStack.empty(); + return ddsim->ready && !ddsim->previousInstructionStack.empty(); } bool ddsimIsFinished(SimulationState* self) { diff --git a/src/backend/dd/DDSimDiagnostics.cpp b/src/backend/dd/DDSimDiagnostics.cpp index 7619adb..c603951 100644 --- a/src/backend/dd/DDSimDiagnostics.cpp +++ b/src/backend/dd/DDSimDiagnostics.cpp @@ -152,6 +152,10 @@ size_t tryFindMissingInteraction(DDDiagnostics* diagnostics, DDSimulationState* state, size_t instruction, const std::unique_ptr& assertion, ErrorCause* output, size_t count) { + if (count == 0) { + return 0; + } + auto targets = assertion->getTargetQubits(); auto outputs = Span(output, count); std::vector targetQubits(targets.size()); @@ -191,6 +195,10 @@ size_t tryFindMissingInteraction(DDDiagnostics* diagnostics, size_t tryFindZeroControls(DDDiagnostics* diagnostics, size_t instruction, ErrorCause* output, size_t count) { + if (count == 0) { + return 0; + } + std::vector dependencies( diagnostics->interface.getInstructionCount(&diagnostics->interface)); diagnostics->interface.getDataDependencies( diff --git a/src/common/parsing/AssertionParsing.cpp b/src/common/parsing/AssertionParsing.cpp index a63dfef..ae5de88 100644 --- a/src/common/parsing/AssertionParsing.cpp +++ b/src/common/parsing/AssertionParsing.cpp @@ -85,7 +85,7 @@ Complex parseComplex(std::string complexString) { double real = 0; double imaginary = 0; for (auto& part : parts) { - if (part.find('i') != std::string::npos && + if (part.find('i') != std::string::npos || part.find('j') != std::string::npos) { imaginary += std::stod(replaceString(replaceString(part, "i", ""), "j", "")); @@ -151,7 +151,8 @@ std::unique_ptr parseAssertion(std::string assertionString, } catch (const std::invalid_argument& e) { similarityThreshold = 1.0; } catch (const std::out_of_range& e) { - similarityThreshold = 1.0; + throw ParsingError( + "Similarity threshold out of range. It must be between 0 and 1"); } if (blockContent.find(';') == std::string::npos) { diff --git a/src/common/parsing/CodePreprocessing.cpp b/src/common/parsing/CodePreprocessing.cpp index c401957..810ea52 100644 --- a/src/common/parsing/CodePreprocessing.cpp +++ b/src/common/parsing/CodePreprocessing.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -204,7 +203,7 @@ preprocessCode(const std::string& code, size_t startIndex, if (isFunctionDefinition(line)) { if (!block.valid) { - throw std::runtime_error("Gate definitions require a body block"); + throw ParsingError("Gate definitions require a body block"); } const auto f = parseFunctionDefinition(line); functionDefinitions.insert({f.name, f}); diff --git a/test/circuits/failing-assertions-multiple-causes.qasm b/test/circuits/failing-assertions-multiple-causes.qasm new file mode 100644 index 0000000..aaed9d2 --- /dev/null +++ b/test/circuits/failing-assertions-multiple-causes.qasm @@ -0,0 +1,6 @@ +qreg q[5]; // 0 + +cx q[0], q[1]; // 1 +cx q[0], q[2]; // 2 + +assert-ent q[0], q[1], q[2], q[3], q[4]; // 3 (fails) diff --git a/test/circuits/failing-assertions-multiple-missing-interaction.qasm b/test/circuits/failing-assertions-multiple-missing-interaction.qasm new file mode 100644 index 0000000..16d8393 --- /dev/null +++ b/test/circuits/failing-assertions-multiple-missing-interaction.qasm @@ -0,0 +1,5 @@ +qreg q[5]; // 0 + +h q[0]; // 1 + +assert-ent q[0], q[1], q[2], q[3], q[4]; // 2 (fails) diff --git a/test/circuits/failing-assertions-multiple-zero-controls.qasm b/test/circuits/failing-assertions-multiple-zero-controls.qasm new file mode 100644 index 0000000..2833e39 --- /dev/null +++ b/test/circuits/failing-assertions-multiple-zero-controls.qasm @@ -0,0 +1,7 @@ +qreg q[4]; // 0 + +cx q[0], q[1]; // 1 +cx q[0], q[2]; // 2 +cx q[0], q[3]; // 3 + +assert-ent q[0], q[1], q[2], q[3]; // 4 (fails) diff --git a/test/test_custom_code.cpp b/test/test_custom_code.cpp index dbeccad..ea3e6b4 100644 --- a/test/test_custom_code.cpp +++ b/test/test_custom_code.cpp @@ -23,7 +23,8 @@ class CustomCodeTest : public testing::Test { std::string userCode; size_t offset = 0; - void loadCode(size_t numQubits, size_t numClassics, const char* code) { + void loadCode(size_t numQubits, size_t numClassics, const char* code, + bool shouldFail = false) { if (numQubits < 1) { numQubits = 1; } @@ -41,7 +42,8 @@ class CustomCodeTest : public testing::Test { userCode = code; fullCode = ss.str(); - state->loadCode(state, fullCode.c_str()); + ASSERT_EQ(state->loadCode(state, fullCode.c_str()), + shouldFail ? ERROR : OK); } void forwardTo(size_t instruction) { @@ -68,6 +70,8 @@ TEST_F(CustomCodeTest, ClassicControlledOperation) { state->getStateVectorFull(state, &sv); ASSERT_TRUE(complexEquality(amplitudes[0], 1, 0.0) || complexEquality(amplitudes[1], 1, 0.0)); + + ASSERT_EQ(state->stepBackward(state), OK); } TEST_F(CustomCodeTest, ResetGate) { @@ -167,3 +171,85 @@ TEST_F(CustomCodeTest, LegalSubstateCircuitEqualityAssertion) { ASSERT_EQ(state->runAll(state, &numErrors), OK); ASSERT_EQ(numErrors, 0); } + +TEST_F(CustomCodeTest, ErrorInCode) { + loadCode(3, 0, "x f[0];", true); + size_t numErrors = 0; + ASSERT_EQ(state->runAll(state, &numErrors), ERROR); + ASSERT_EQ(numErrors, 0); + ASSERT_EQ(state->runSimulation(state), ERROR); + ASSERT_EQ(state->runSimulationBackward(state), ERROR); +} + +TEST_F(CustomCodeTest, StackTraceErrorInCode) { + loadCode(3, 0, "x f[0];", true); + size_t depth = 0; + ASSERT_EQ(state->getStackDepth(state, &depth), ERROR); + ASSERT_EQ(state->getStackTrace(state, 10, nullptr), ERROR); +} + +TEST_F(CustomCodeTest, ErrorAssertionInCircuitEqualityAssertion) { + loadCode(3, 0, + "x q[0];" + "assert-eq q[0], q[1], q[2] { qreg q[3]; assert-sup q[0]; }"); + ASSERT_EQ(state->runAll(state, nullptr), ERROR); +} + +TEST_F(CustomCodeTest, BarrierInstruction) { + loadCode(1, 0, + "barrier;" + "x q[0];"); + ASSERT_EQ(state->stepForward(state), OK); + ASSERT_EQ(state->stepForward(state), OK); + + ASSERT_EQ(state->stepForward(state), OK); + ASSERT_EQ(state->stepBackward(state), OK); + ASSERT_EQ(state->stepOverForward(state), OK); + ASSERT_EQ(state->stepOverBackward(state), OK); +} + +TEST_F(CustomCodeTest, ErrorAssertionInvalidIndex) { + loadCode(3, 0, + "x q[0];" + "assert-sup q[3];"); + ASSERT_EQ(state->runAll(state, nullptr), ERROR); +} + +TEST_F(CustomCodeTest, ErrorAssertionInvalidQubit) { + loadCode(3, 0, + "x q[0];" + "assert-sup f[3];"); + ASSERT_EQ(state->runAll(state, nullptr), ERROR); +} + +TEST_F(CustomCodeTest, AssertionInCustomGate) { + loadCode(3, 0, + "gate test q0 {" + "h q0;" + "assert-sup q0;" + "}" + "test q[0];"); + size_t errors = 0; + ASSERT_EQ(state->runAll(state, &errors), OK); + ASSERT_EQ(errors, 0); +} + +TEST_F(CustomCodeTest, AssertionInCustomGateShadowing) { + loadCode(3, 0, + "gate test q {" + "h q;" + "assert-sup q;" + "}" + "test q[0];"); + size_t errors = 0; + ASSERT_EQ(state->runAll(state, &errors), OK); + ASSERT_EQ(errors, 0); +} + +TEST_F(CustomCodeTest, CommentAtEnd) { + loadCode(3, 0, "x q[0]; // Comment"); + size_t errors = 0; + ASSERT_EQ(state->runAll(state, &errors), OK); + ASSERT_EQ(errors, 0); + ASSERT_EQ(state->getCurrentInstruction(state), 3); +} diff --git a/test/test_data_retrieval.cpp b/test/test_data_retrieval.cpp index 7fe1557..fd0a0b0 100644 --- a/test/test_data_retrieval.cpp +++ b/test/test_data_retrieval.cpp @@ -174,3 +174,16 @@ TEST_F(DataRetrievalTest, GetStateVectorSub) { ASSERT_TRUE(complexEquality(amplitudes[2], 0.0, 0.0)); ASSERT_TRUE(complexEquality(amplitudes[3], 0.0, 0.0)); } + +TEST_F(DataRetrievalTest, GetUnknownClassicalVariable) { + Variable v; + + forwardTo(6); + ASSERT_EQ(state->getClassicalVariable(state, "u[0]", &v), ERROR); +} + +TEST_F(DataRetrievalTest, GetBadClassicalVariableName) { + std::array name = {0}; + forwardTo(6); + ASSERT_EQ(state->getClassicalVariableName(state, 5, name.data()), ERROR); +} diff --git a/test/test_diagnostics.cpp b/test/test_diagnostics.cpp index 4209c5a..ca264e2 100644 --- a/test/test_diagnostics.cpp +++ b/test/test_diagnostics.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include class DiagnosticsTest : public testing::Test { @@ -72,6 +73,18 @@ TEST_F(DiagnosticsTest, ControlAlwaysZeroTest) { ASSERT_EQ(problems[0].instruction, 4); } +TEST_F(DiagnosticsTest, MaximumControlAlwaysZeroTest) { + loadFromFile("failing-assertions-multiple-zero-controls"); + state->runSimulation(state); + std::array problems{}; + ASSERT_EQ(diagnostics->potentialErrorCauses(diagnostics, problems.data(), 10), + 3); + ASSERT_EQ(diagnostics->potentialErrorCauses(diagnostics, problems.data(), 3), + 3); + ASSERT_EQ(diagnostics->potentialErrorCauses(diagnostics, problems.data(), 2), + 2); +} + TEST_F(DiagnosticsTest, MissingInteraction) { loadFromFile("failing-assertions-missing-interaction"); state->runSimulation(state); @@ -83,3 +96,68 @@ TEST_F(DiagnosticsTest, MissingInteraction) { ASSERT_EQ(problems[0].type, ErrorCauseType::MissingInteraction); ASSERT_EQ(problems[0].instruction, 7); } + +TEST_F(DiagnosticsTest, MaximumMissingInteraction) { + loadFromFile("failing-assertions-multiple-missing-interaction"); + state->runSimulation(state); + ASSERT_EQ(state->getCurrentInstruction(state), 2); + std::array problems{}; + ASSERT_EQ(diagnostics->potentialErrorCauses(diagnostics, problems.data(), 20), + 10); + ASSERT_EQ(diagnostics->potentialErrorCauses(diagnostics, problems.data(), 10), + 10); + ASSERT_EQ(diagnostics->potentialErrorCauses(diagnostics, problems.data(), 3), + 3); +} + +TEST_F(DiagnosticsTest, MaximumMultipleCauses) { + loadFromFile("failing-assertions-multiple-causes"); + state->runSimulation(state); + ASSERT_EQ(state->getCurrentInstruction(state), 3); + std::array problems{}; + const std::vector maxErrors = {20, 8, 7, 4}; + const std::vector>> + expectedTypes = { + {9, + {MissingInteraction, MissingInteraction, MissingInteraction, + MissingInteraction, MissingInteraction, MissingInteraction, + MissingInteraction, ControlAlwaysZero, ControlAlwaysZero}}, + {8, + {MissingInteraction, MissingInteraction, MissingInteraction, + MissingInteraction, MissingInteraction, MissingInteraction, + MissingInteraction, ControlAlwaysZero}}, + {7, + {MissingInteraction, MissingInteraction, MissingInteraction, + MissingInteraction, MissingInteraction, MissingInteraction, + MissingInteraction}}, + {4, + {MissingInteraction, MissingInteraction, MissingInteraction, + MissingInteraction}}, + }; + for (size_t i = 0; i < maxErrors.size(); i++) { + const auto [expectedCount, types] = expectedTypes[i]; + ASSERT_EQ(diagnostics->potentialErrorCauses(diagnostics, problems.data(), + maxErrors[i]), + expectedCount); + for (size_t j = 0; j < expectedCount; j++) { + ASSERT_EQ(problems.at(j).type, types[j]); + } + } +} + +TEST_F(DiagnosticsTest, NoFailedAssertions) { + loadFromFile("complex-jumps"); + state->runSimulation(state); + std::array problems{}; + ASSERT_EQ(diagnostics->potentialErrorCauses(diagnostics, problems.data(), 5), + 0); +} + +TEST_F(DiagnosticsTest, RequestZeroProblems) { + loadFromFile("failing-assertions"); + state->runSimulation(state); + std::array problems{}; + const size_t count = + diagnostics->potentialErrorCauses(diagnostics, problems.data(), 0); + ASSERT_EQ(count, 0); +} diff --git a/test/test_parsing.cpp b/test/test_parsing.cpp index f49a188..e0f2c27 100644 --- a/test/test_parsing.cpp +++ b/test/test_parsing.cpp @@ -1,6 +1,9 @@ +#include "common/Span.hpp" #include "common/parsing/AssertionParsing.hpp" +#include "common/parsing/CodePreprocessing.hpp" #include "common/parsing/ParsingError.hpp" +#include #include #include #include @@ -62,3 +65,42 @@ TEST_F(ParsingTest, ErrorCircuitEqualityAssertion) { TEST_F(ParsingTest, ErrorInvalidAssertion) { ASSERT_THROW(parseAssertion("assert-fake q[0]", ""), ParsingError); } + +TEST_F(ParsingTest, ComplexNumberParsing) { + // With statevector + const auto a1 = parseAssertion("assert-eq 0.5, q[0], q[1]", + "0.5j, 0.5i, 0.5 + 0i, 0 + 0.5j"); + ASSERT_EQ(a1->getType(), AssertionType::StatevectorEquality); + ASSERT_EQ(a1->getTargetQubits().size(), 2); + const auto* sv = dynamic_cast(a1.get()); + const Span amplitudes(sv->getTargetStatevector().amplitudes, + sv->getTargetStatevector().numStates); + for (size_t i = 0; i < 4; i++) { + ASSERT_EQ(amplitudes[i].real, i != 2 ? 0.0 : 0.5); + ASSERT_EQ(amplitudes[i].imaginary, i != 2 ? 0.5 : 0.0); + } +} + +TEST_F(ParsingTest, ComplexNumberParsingErrorBadSimilarity) { + // Similarity > 1 + ASSERT_THROW(parseAssertion("assert-eq 2, q[0]", "1, 0"), ParsingError); + + // Similarity out of double range + ASSERT_THROW(parseAssertion("assert-eq 1e500, q[0]", "1, 0"), ParsingError); +} + +TEST_F(ParsingTest, BadGateDefinition) { + const std::string input = "gate my_gate q0;"; + std::string output; + ASSERT_THROW(preprocessCode(input, output), ParsingError); +} + +TEST_F(ParsingTest, BadFunctionCall) { + const std::string input = + "gate my_gate q0, q1 { h q0; h q1 } qreg q[3]; my_gate q[0];"; + std::string output; + ASSERT_THROW(preprocessCode(input, output), ParsingError); + const std::string input2 = + "gate my_gate q0, q1 { h q0; h q1 } qreg q[3]; my_gate q[0], q[1], q[2];"; + ASSERT_THROW(preprocessCode(input2, output), ParsingError); +} diff --git a/test/test_simulation.cpp b/test/test_simulation.cpp index 34bf0f3..d058758 100644 --- a/test/test_simulation.cpp +++ b/test/test_simulation.cpp @@ -125,7 +125,7 @@ TEST_P(SimulationTest, StackTraceRetrieval) { ASSERT_EQ(depth, exp) << "Depth computation failed for instruction " << state->getCurrentInstruction(state) << " at index " << index << " in " << GetParam() << "\n"; - for (size_t depthToTest = 1; depthToTest <= depth; depthToTest++) { + for (size_t depthToTest = 1; depthToTest <= depth + 1; depthToTest++) { std::vector stack(depthToTest); ASSERT_EQ(state->getStackTrace(state, depthToTest, stack.data()), Result::OK) @@ -134,7 +134,7 @@ TEST_P(SimulationTest, StackTraceRetrieval) { << " in " << GetParam() << "\n"; const std::vector& expectedStack = expectedStacks.at(GetParam()).at(index); - for (size_t i = 0; i < depthToTest; i++) { + for (size_t i = 0; i < (depthToTest > depth ? depth : depthToTest); i++) { ASSERT_EQ(stack[i], expectedStack[i]) << "Failed for index " << i << " at depth " << depthToTest << " for instruction " << state->getCurrentInstruction(state) @@ -181,6 +181,9 @@ TEST_P(SimulationTest, TopLevelBreakpoints) { ASSERT_TRUE(state->wasBreakpointHit(state)); } + ASSERT_EQ(state->runSimulationBackward(state), Result::OK); + ASSERT_TRUE(state->wasBreakpointHit(state)); + ASSERT_EQ(state->clearBreakpoints(state), Result::OK) << "Failed to clear breakpoints in " << GetParam() << "\n"; ASSERT_EQ(state->runSimulationBackward(state), Result::OK); @@ -224,6 +227,60 @@ TEST_P(SimulationTest, PauseSimulation) { ASSERT_NE(state->getCurrentInstruction(state), currentPosition) << "Simulation still paused after second 'step over' in " << GetParam() << "\n"; + + if (GetParam() != "complex-jumps") { + return; + } + + // test stepOverForward after pause at CALL instruction (will pause + // immediately) + ASSERT_EQ(state->resetSimulation(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->pauseSimulation(state), Result::OK); + ASSERT_EQ(state->stepOverForward(state), Result::OK); + ASSERT_EQ(state->getCurrentInstruction(state), 12); + + // test stepOutForward after pause inside custom gate (will run one more + // instruction) + ASSERT_EQ(state->resetSimulation(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->pauseSimulation(state), Result::OK); + ASSERT_EQ(state->stepOutForward(state), Result::OK); + ASSERT_EQ(state->getCurrentInstruction(state), 6); + + // test stepOverBackward after pause at RETURN instruction (will pause + // immediately) + ASSERT_EQ(state->resetSimulation(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepOverForward(state), Result::OK); + ASSERT_EQ(state->pauseSimulation(state), Result::OK); + ASSERT_EQ(state->stepOverBackward(state), Result::OK); + ASSERT_EQ(state->getCurrentInstruction(state), 7); + + // test stepOutBackward after pause inside custom gate (will run one more + // instruction) + ASSERT_EQ(state->resetSimulation(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->pauseSimulation(state), Result::OK); + ASSERT_EQ(state->stepOutBackward(state), Result::OK); + ASSERT_EQ(state->getCurrentInstruction(state), 5); } TEST_P(SimulationTest, ResetSimulation) { @@ -327,6 +384,10 @@ TEST_P(SimulationTest, RunSimulation) { } TEST_P(SimulationTest, InGateDefinitionBreakpoints) { + if (GetParam() != "complex-jumps") { + return; + } + const std::map> breakpointPositions = { {"complex-jumps", {86, 280, 411}}, {"failing-assertions", {}}}; const std::map> @@ -364,6 +425,26 @@ TEST_P(SimulationTest, InGateDefinitionBreakpoints) { ASSERT_TRUE(state->wasBreakpointHit(state)); } + // Test specific step instructions with breakpoints + ASSERT_EQ(state->resetSimulation(state), Result::OK); + ASSERT_EQ(state->runSimulation(state), Result::OK); + ASSERT_EQ(state->stepOutBackward(state), Result::OK); + ASSERT_EQ(state->stepOverForward(state), Result::OK); + ASSERT_EQ(state->getCurrentInstruction(state), 2); + ASSERT_EQ(state->stepOutForward(state), Result::OK); + ASSERT_EQ(state->stepOverBackward(state), Result::OK); + ASSERT_EQ(state->getCurrentInstruction(state), 2); + ASSERT_EQ(state->runSimulation(state), Result::OK); + ASSERT_EQ(state->runSimulation(state), Result::OK); + ASSERT_EQ(state->getCurrentInstruction(state), 7); + ASSERT_EQ(state->stepBackward(state), Result::OK); + ASSERT_EQ(state->stepOutForward(state), Result::OK); + ASSERT_EQ(state->getCurrentInstruction(state), 7); + ASSERT_EQ(state->stepForward(state), Result::OK); + ASSERT_EQ(state->stepOutBackward(state), Result::OK); + ASSERT_EQ(state->getCurrentInstruction(state), 7); + + // Test deleting breakpoints ASSERT_EQ(state->clearBreakpoints(state), Result::OK) << "Failed to clear breakpoints in " << GetParam() << "\n"; ASSERT_EQ(state->runSimulationBackward(state), Result::OK); @@ -376,6 +457,23 @@ TEST_P(SimulationTest, InGateDefinitionBreakpoints) { } } +TEST_P(SimulationTest, StepAtEnds) { + size_t errors = 0; + state->runAll(state, &errors); + ASSERT_EQ(state->stepOverForward(state), Result::ERROR); + ASSERT_EQ(state->stepForward(state), Result::ERROR); + ASSERT_EQ(state->stepOutForward(state), Result::ERROR); + ASSERT_EQ(state->resetSimulation(state), Result::OK); + ASSERT_EQ(state->stepOverBackward(state), Result::ERROR); + ASSERT_EQ(state->stepBackward(state), Result::ERROR); + ASSERT_EQ(state->stepOutBackward(state), Result::ERROR); +} + +TEST_P(SimulationTest, BreakpointOutside) { + size_t location = 0; + ASSERT_EQ(state->setBreakpoint(state, 9999, &location), ERROR); +} + INSTANTIATE_TEST_SUITE_P(StringParams, SimulationTest, ::testing::Values("complex-jumps", "failing-assertions")); diff --git a/test/test_utility.cpp b/test/test_utility.cpp index 6cb2bf0..e230abe 100644 --- a/test/test_utility.cpp +++ b/test/test_utility.cpp @@ -1,5 +1,6 @@ #include "backend/dd/DDSimDebug.hpp" #include "backend/debug.h" +#include "common.h" #include "utils_test.hpp" #include @@ -45,3 +46,11 @@ TEST_F(UtilityTest, GetInstructionPosition) { << "Failed for instruction " << instruction; } } + +TEST_F(UtilityTest, BadInstructionPosition) { + loadFromFile("complex-jumps"); + + size_t start = 0; + size_t end = 0; + ASSERT_EQ(state->getInstructionPosition(state, 100, &start, &end), ERROR); +}