Skip to content

Commit

Permalink
Unit tests for Grovers, Measure nodes (#91)
Browse files Browse the repository at this point in the history
* fixed invalid input test case in grovers, fixed typo in grover's documentation

* fixed test case with error condition on grovers node

* fixed other Local simulator node tests failing because of Grovers test

* added a test util generic function to validate output based on input, added test case for Measure Node, fixed Quantum Circuit node to store a reference to shell instance, to be able to stop it in tests later

* refactored grovers_spec.js to use testUtil function to validate output

* removing shel reference in quantum-circuit node instance

* Lint code

* fixed issue with error condition testing

* moved commits from master to unit-tests branch

* Fix shors_spec.js formatting

* Re-enable disabled shors tests

* Increase timeout for shors test

- Increase timeout for `return success output on valid input` test to
  25000ms.
- Reduce timeout for all tests from 15000ms to 10000ms.

Co-authored-by: Louis Lefevre <[email protected]>
  • Loading branch information
ttoktassynov and louislefevre authored Aug 26, 2021
1 parent f5fae5a commit aa94963
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 33 deletions.
1 change: 1 addition & 0 deletions nodes/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ module.exports = {
INVALID_REGISTER_NUMBER,
QUBITS_FROM_DIFFERENT_CIRCUITS,
SAME_QUBIT_RECEIVED_TWICE,
NOT_BIT_STRING,
BLOCH_SPHERE_WITH_MEASUREMENT,
GREATER_THAN_TWO,
INPUT_ODD_INTEGER,
Expand Down
1 change: 1 addition & 0 deletions nodes/quantum-algorithms/grovers/grovers.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module.exports = function(RED) {
function GroversNode(config) {
RED.nodes.createNode(this, config);
this.name = config.name || 'Grovers';
const node = this;

this.on('input', async function(msg, send, done) {
let error = errors.validateGroversInput(msg);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"setup": "(npm run link && npm run venv) && echo Setup complete - run 'npm start' to open Node-RED",
"link": "bash bin/link.sh || bin/link.sh",
"venv": "bash bin/pyvenv.sh || bin/pyvenv.sh",
"test": "mocha \"test/**/*_spec.js\" --timeout 15000",
"test": "mocha \"test/**/*_spec.js\" --timeout 10000",
"clean": "rm -r venv/ & npm uninstall --prefix ~/.node-red/ node-red-contrib-quantum",
"lint": "eslint --fix --ignore-path .gitignore .",
"postinstall": "npm run venv"
Expand Down
45 changes: 25 additions & 20 deletions test/nodes/grovers_spec.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
const groversNode = require('../../nodes/quantum-algorithms/grovers/grovers.js');
const testUtil = require('../test-util');
const nodeTestHelper = testUtil.nodeTestHelper;
const {FlowBuilder} = require('../flow-builder');
const errors = require('../../nodes/errors');
const assert = require('chai').assert;


describe('GroversNode', function() {
beforeEach(function(done) {
nodeTestHelper.startServer(done);
Expand All @@ -19,34 +20,38 @@ describe('GroversNode', function() {
});

it('default name outputs correctly', function(done) {
let flow = [{id: 'groversNode', type: 'grovers', wires: []}];
nodeTestHelper.load(groversNode, flow, function() {
flow = new FlowBuilder();
flow.add('grovers', 'groversNode', []);

nodeTestHelper.load(flow.nodes, flow.flow, function() {
let groversTestNode = nodeTestHelper.getNode('groversNode');
groversTestNode.should.have.property('name', 'Grovers');
groversTestNode.should.have.property('name', 'grovers');
done();
});
});

it('return success output on valid input', function(done) {
let flow = [{id: 'groversNode', type: 'grovers', wires: [['helperNode']]},
{id: 'helperNode', type: 'helper'}];
flow = new FlowBuilder();
flow.add('grovers', 'n1', [['n2']]);
flow.addOutput('n2');

const givenInput = {payload: '111111'};
const expectedOutput = {topMeasurement: '111111', iterationsNum: 6};
testUtil.correctOutputReceived(flow, givenInput, expectedOutput, done);
});

it('should fail on invalid input', function(done) {
flow = new FlowBuilder();
flow.add('grovers', 'groversNode', []);

nodeTestHelper.load(groversNode, flow, function() {
nodeTestHelper.load(flow.nodes, flow.flow, function() {
let groversTestNode = nodeTestHelper.getNode('groversNode');
let helperNode = nodeTestHelper.getNode('helperNode');

helperNode.on('input', function(msg) {
const expectedPayload = {topMeasurement: '111111', iterationsNum: 6};
try {
assert.strictEqual(msg.payload.topMeasurement, expectedPayload.topMeasurement);
assert.strictEqual(msg.payload.iterationsNum, expectedPayload.iterationsNum);
done();
} catch (err) {
done(err);
}
groversTestNode.on('call:error', (call)=> {
const actualError = call.firstArg;
assert.strictEqual(actualError.message, errors.NOT_BIT_STRING);
done();
});

groversTestNode.receive({payload: '111111'});
groversTestNode.receive({payload: '111112'});
});
});
});
16 changes: 16 additions & 0 deletions test/nodes/measure_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,20 @@ describe('MeasureNode', function() {

testUtil.commandExecuted(flow, command, done);
});

it('should return correct output', function(done) {
let flow = new FlowBuilder();

flow.add('quantum-circuit', 'n0', [['n1']],
{structure: 'qubits', outputs: '1', qbitsreg: '1', cbitsreg: '1'});
flow.add('not-gate', 'n1', [['n2']]);
flow.add('measure', 'n2', [['n3']], {selectedBit: '0'});
flow.add('local-simulator', 'n3', [['n4']], {shots: 1});
flow.addOutput('n4');

const givenInput = 'dummy input';
const expectedOutput = {1: 1};

testUtil.correctOutputReceived(flow, givenInput, expectedOutput, done);
});
});
25 changes: 13 additions & 12 deletions test/nodes/shors_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ describe('ShorsNode', function() {
nodeTestHelper.stopServer(done);
});

xit('load node', function(done) {
it('load node', function(done) {
testUtil.isLoaded(shorsNode, 'shors', done);
});

xit('default name outputs correctly', function(done) {
it('default name outputs correctly', function(done) {
flow = new FlowBuilder();
flow.add('shors', 'shorsNode', [[]]);

Expand All @@ -29,6 +29,7 @@ describe('ShorsNode', function() {
done();
});
});

it('return success output on valid input', function(done) {
flow = new FlowBuilder();
flow.add('shors', 'shorsNode', [['helperNode']]);
Expand All @@ -50,50 +51,50 @@ describe('ShorsNode', function() {

inputNode.receive({payload: 15});
});
});
}).timeout(25000);

it('return error for input less than 3', function(done){
it('return error for input less than 3', function(done) {
flow = new FlowBuilder();
flow.add('shors', 'shorsNode', []);

nodeTestHelper.load(flow.nodes, flow.flow, function(){
nodeTestHelper.load(flow.nodes, flow.flow, function() {
let shorsTestNode = nodeTestHelper.getNode('shorsNode');
shorsTestNode.on('call:error', (call)=> {
const actualError = call.firstArg;
assert.strictEqual(actualError.message, errors.GREATER_THAN_TWO);
done();
});
shorsTestNode.receive({payload: 1});
})
});
});

it('return error for even input', function(done){
it('return error for even input', function(done) {
flow = new FlowBuilder();
flow.add('shors', 'shorsNode', []);

nodeTestHelper.load(flow.nodes, flow.flow, function(){
nodeTestHelper.load(flow.nodes, flow.flow, function() {
let shorsTestNode = nodeTestHelper.getNode('shorsNode');
shorsTestNode.on('call:error', (call)=> {
const actualError = call.firstArg;
assert.strictEqual(actualError.message, errors.INPUT_ODD_INTEGER);
done();
});
shorsTestNode.receive({payload: 4});
})
});
});

it('return error for non-integer input', function(done){
it('return error for non-integer input', function(done) {
flow = new FlowBuilder();
flow.add('shors', 'shorsNode', []);

nodeTestHelper.load(flow.nodes, flow.flow, function(){
nodeTestHelper.load(flow.nodes, flow.flow, function() {
let shorsTestNode = nodeTestHelper.getNode('shorsNode');
shorsTestNode.on('call:error', (call)=> {
const actualError = call.firstArg;
assert.strictEqual(actualError.message, errors.INPUT_AN_INTEGER);
done();
});
shorsTestNode.receive({payload: 'a'});
})
});
});
});
19 changes: 19 additions & 0 deletions test/test-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,27 @@ function commandExecuted(flowBuilder, command, done) {
});
}

function correctOutputReceived(flow, givenInput, expectedOutput, done) {
nodeTestHelper.load(flow.nodes, flow.flow, function() {
const inputNode = nodeTestHelper.getNode(flow.inputId);
const outputNode = nodeTestHelper.getNode(flow.outputId);
outputNode.on('input', function(msg) {
try {
assert.deepEqual(msg.payload, expectedOutput);
done();
} catch (err) {
done(err);
} finally {
shell.stop();
}
});
inputNode.receive(givenInput);
});
}

module.exports = {
nodeTestHelper,
isLoaded,
commandExecuted,
correctOutputReceived,
};

0 comments on commit aa94963

Please sign in to comment.