From 66f4bf2ec78912672bba09b35ed0c0b8a8af8f1d Mon Sep 17 00:00:00 2001 From: Greg S Date: Thu, 2 May 2019 12:46:48 +0200 Subject: [PATCH] nemtech/NIP#21 : improved unit tests for QR generation and schema definition --- src/QRCode.ts | 4 +- src/QRCodeGenerator.ts | 2 +- src/QRCodeSettings.ts | 26 ++++++ test/AccountQR.spec.ts | 61 ++++++++++++++ test/ContactQR.spec.ts | 61 ++++++++++++++ test/QRCode.spec.ts | 149 +++++++++++++++++++++++++++++++++++ test/QRCodeGenerator.spec.ts | 3 + test/TransactionQR.spec.ts | 73 +++++++++++++++++ 8 files changed, 377 insertions(+), 2 deletions(-) create mode 100644 test/AccountQR.spec.ts create mode 100644 test/ContactQR.spec.ts create mode 100644 test/QRCode.spec.ts create mode 100644 test/TransactionQR.spec.ts diff --git a/src/QRCode.ts b/src/QRCode.ts index 68caacb..18ce7fb 100644 --- a/src/QRCode.ts +++ b/src/QRCode.ts @@ -16,6 +16,7 @@ import { QRCode as QRCodeImpl, QR8BitByte, + ErrorCorrectLevel, } from 'qrcode-generator-ts'; import { @@ -81,7 +82,8 @@ export abstract class QRCode implements QRCodeInterface { // prepare QR generation const qr = new QRCodeImpl(); - qr.setTypeNumber(40); + qr.setTypeNumber(QRCodeSettings.VERSION_NUMBER); + qr.setErrorCorrectLevel(QRCodeSettings.CORRECTION_LEVEL); // get JSON representation const json = this.toJSON(); diff --git a/src/QRCodeGenerator.ts b/src/QRCodeGenerator.ts index bd4c5fb..545536b 100644 --- a/src/QRCodeGenerator.ts +++ b/src/QRCodeGenerator.ts @@ -73,4 +73,4 @@ export class QRCodeGenerator { ): TransactionQR { return new TransactionQR(transaction, networkType, chainId); } -}; \ No newline at end of file +} diff --git a/src/QRCodeSettings.ts b/src/QRCodeSettings.ts index 3188275..a206a0a 100644 --- a/src/QRCodeSettings.ts +++ b/src/QRCodeSettings.ts @@ -13,6 +13,10 @@ * See the License for the specific language governing permissions and *limitations under the License. */ +import { + ErrorCorrectLevel, +} from 'qrcode-generator-ts'; + // internal dependencies import {QRCodeType} from '../index'; @@ -24,6 +28,28 @@ import {QRCodeType} from '../index'; */ export class QRCodeSettings { + /** + * The Error correction level. + * + * @var {ErrorCorrectLevel} + */ + public static CORRECTION_LEVEL = ErrorCorrectLevel.L; + + /** + * The QR Code version number. + * + * With `40-L` configuration, the QR Code can contain + * up to `2953` bytes. As defined in the following link, + * this is the maximum storage capacity for our types + * or QR Codes: + * + * https://en.wikipedia.org/wiki/QR_code#Design + * + * @see https://en.wikipedia.org/wiki/QR_code#Design + * @var {string} + */ + public static VERSION_NUMBER = 40; + /** * The QR Code cell size in pixels. * diff --git a/test/AccountQR.spec.ts b/test/AccountQR.spec.ts new file mode 100644 index 0000000..79a973b --- /dev/null +++ b/test/AccountQR.spec.ts @@ -0,0 +1,61 @@ +/** + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + *limitations under the License. + */ +import {expect} from "chai"; +import { + Account, + NetworkType, +} from 'nem2-sdk'; +import { + QRCode as QRCodeImpl, + QR8BitByte, + ErrorCorrectLevel, +} from 'qrcode-generator-ts'; + +// internal dependencies +import { + QRCodeInterface, + QRCode, + QRCodeType, + QRCodeSettings, + ContactQR, +} from "../index"; + +describe('AccountQR -->', () => { + + describe('toJSON() should', () => { + + it('include mandatory NIP-7 QR Code base fields', () => { + // Arrange: + const account = Account.createFromPrivateKey( + 'F97AE23C2A28ECEDE6F8D6C447C0A10B55C92DDE9316CCD36C3177B073906978', + NetworkType.TEST_NET + ); + + // Act: + const addContact = new ContactQR(account, NetworkType.TEST_NET, ''); + const actualJSON = addContact.toJSON(); + const actualObject = JSON.parse(actualJSON); + + // Assert: + expect(actualObject).to.have.property('v'); + expect(actualObject).to.have.property('type'); + expect(actualObject).to.have.property('network_id'); + expect(actualObject).to.have.property('chain_id'); + expect(actualObject).to.have.property('data'); + }); + }); + +}); diff --git a/test/ContactQR.spec.ts b/test/ContactQR.spec.ts new file mode 100644 index 0000000..c74f0c3 --- /dev/null +++ b/test/ContactQR.spec.ts @@ -0,0 +1,61 @@ +/** + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + *limitations under the License. + */ +import {expect} from "chai"; +import { + PublicAccount, + NetworkType, +} from 'nem2-sdk'; +import { + QRCode as QRCodeImpl, + QR8BitByte, + ErrorCorrectLevel, +} from 'qrcode-generator-ts'; + +// internal dependencies +import { + QRCodeInterface, + QRCode, + QRCodeType, + QRCodeSettings, + ContactQR, +} from "../index"; + +describe('ContactQR -->', () => { + + describe('toJSON() should', () => { + + it('include mandatory NIP-7 QR Code base fields', () => { + // Arrange: + const account = PublicAccount.createFromPublicKey( + 'C5C55181284607954E56CD46DE85F4F3EF4CC713CC2B95000FA741998558D268', + NetworkType.TEST_NET + ); + + // Act: + const addContact = new ContactQR(account, NetworkType.TEST_NET, ''); + const actualJSON = addContact.toJSON(); + const actualObject = JSON.parse(actualJSON); + + // Assert: + expect(actualObject).to.have.property('v'); + expect(actualObject).to.have.property('type'); + expect(actualObject).to.have.property('network_id'); + expect(actualObject).to.have.property('chain_id'); + expect(actualObject).to.have.property('data'); + }); + }); + +}); diff --git a/test/QRCode.spec.ts b/test/QRCode.spec.ts new file mode 100644 index 0000000..cca45b2 --- /dev/null +++ b/test/QRCode.spec.ts @@ -0,0 +1,149 @@ +/** + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + *limitations under the License. + */ +import {expect} from "chai"; +import { + TransferTransaction, + Deadline, + Address, + Mosaic, + NamespaceId, + UInt64, + PlainMessage, + NetworkType, +} from 'nem2-sdk'; +import { + QRCode as QRCodeImpl, + QR8BitByte, + ErrorCorrectLevel, +} from 'qrcode-generator-ts'; + +// internal dependencies +import { + QRCodeInterface, + QRCode, + QRCodeType, + QRCodeSettings, +} from "../index"; + +/// region Mock for QRCode specialization +// extend abstract class for tests +class FakeQR extends QRCode implements QRCodeInterface { + constructor( + public readonly object: Object, + public readonly networkType: NetworkType, + public readonly chainId: string) { + super(QRCodeType.ExportObject, networkType, chainId); + } + + public toJSON(): string { + const jsonSchema = { + 'v': 3, + 'type': this.type, + 'network_id': this.networkType, + 'chain_id': this.chainId, + 'data': this.object, + }; + return JSON.stringify(jsonSchema); + } +} +/// end-region Mock for QRCode specialization + +describe('QRCode -->', () => { + + describe('toBase64() should', () => { + + it('create same Base64 given same objects', () => { + // Arrange: + const object1 = {"test1": "test1"}; + const object2 = {"test1": "test1"}; + + // Act: + const fakeQR1 = new FakeQR(object1, NetworkType.TEST_NET, 'no-chain-id'); + const fakeQR2 = new FakeQR(object2, NetworkType.TEST_NET, 'no-chain-id'); + const implQR1 = fakeQR1.build(); + const implQR2 = fakeQR2.build(); + + // Assert: + expect(fakeQR1.toBase64()).to.be.equal(fakeQR2.toBase64()); + }); + + it('create different Base64 given different objects', () => { + // Arrange: + const object1 = {"test1": "test1"}; + const object2 = {"test2": "test2"}; + + // Act: + const fakeQR1 = new FakeQR(object1, NetworkType.TEST_NET, 'no-chain-id'); + const fakeQR2 = new FakeQR(object2, NetworkType.TEST_NET, 'no-chain-id'); + const implQR1 = fakeQR1.build(); + const implQR2 = fakeQR2.build(); + + // Assert: + expect(fakeQR1.toBase64()).to.not.be.equal(fakeQR2.toBase64()); + }); + }); + + describe('build() should', () => { + + it('set correct settings for QR Code generation', () => { + // Arrange: + const object = {"test": "test"}; + const modulesCount = QRCodeSettings.VERSION_NUMBER * 4 + 17; + + // Act: + const fakeQR = new FakeQR(object, NetworkType.TEST_NET, 'no-chain-id'); + const implQR = fakeQR.build(); + + // Assert: + expect(implQR.getTypeNumber()).to.be.equal(QRCodeSettings.VERSION_NUMBER); + expect(implQR.getErrorCorrectLevel()).to.be.equal(QRCodeSettings.CORRECTION_LEVEL); + expect(implQR.getModuleCount()).to.be.equal(modulesCount); + }); + + it('create same QR codes given same objects', () => { + // Arrange: + const object1 = {"test1": "test1"}; + const object2 = {"test1": "test1"}; + + // Act: + const fakeQR1 = new FakeQR(object1, NetworkType.TEST_NET, 'no-chain-id'); + const fakeQR2 = new FakeQR(object2, NetworkType.TEST_NET, 'no-chain-id'); + const implQR1 = fakeQR1.build(); + const implQR2 = fakeQR2.build(); + + // Assert: + expect(fakeQR1.toJSON()).to.be.equal(fakeQR2.toJSON()); + expect(fakeQR1.toBase64()).to.be.equal(fakeQR2.toBase64()); + }); + + it('create different QR codes given different objects', () => { + // Arrange: + const object1 = {"test1": "test1"}; + const object2 = {"test2": "test2"}; + + // Act: + const fakeQR1 = new FakeQR(object1, NetworkType.TEST_NET, 'no-chain-id'); + const fakeQR2 = new FakeQR(object2, NetworkType.TEST_NET, 'no-chain-id'); + const implQR1 = fakeQR1.build(); + const implQR2 = fakeQR2.build(); + + // Assert: + expect(fakeQR1.toJSON()).to.not.be.equal(fakeQR2.toJSON()); + expect(fakeQR1.toBase64()).to.not.be.equal(fakeQR2.toBase64()); + }); + }); + +}); diff --git a/test/QRCodeGenerator.spec.ts b/test/QRCodeGenerator.spec.ts index 2eb7798..b5d7767 100644 --- a/test/QRCodeGenerator.spec.ts +++ b/test/QRCodeGenerator.spec.ts @@ -52,6 +52,9 @@ describe('QRCodeGenerator -->', () => { }); describe('createTransactionRequest() should', () => { + + //XXX set default TESTNET and CHAIN_ID + it('generate correct Base64 representation for TransferTransaction', () => { // Arrange: const transfer = TransferTransaction.create( diff --git a/test/TransactionQR.spec.ts b/test/TransactionQR.spec.ts new file mode 100644 index 0000000..281f71c --- /dev/null +++ b/test/TransactionQR.spec.ts @@ -0,0 +1,73 @@ +/** + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + *limitations under the License. + */ +import {expect} from "chai"; +import { + TransferTransaction, + Deadline, + Address, + Mosaic, + NamespaceId, + UInt64, + PlainMessage, + NetworkType, +} from 'nem2-sdk'; +import { + QRCode as QRCodeImpl, + QR8BitByte, + ErrorCorrectLevel, +} from 'qrcode-generator-ts'; + +// internal dependencies +import { + QRCodeInterface, + QRCode, + QRCodeType, + QRCodeSettings, + TransactionQR, +} from "../index"; + +describe('TransactionQR -->', () => { + + describe('toJSON() should', () => { + + it('include mandatory NIP-7 QR Code base fields', () => { + // Arrange: + const transfer = TransferTransaction.create( + Deadline.create(), + Address.createFromPublicKey( + 'C5C55181284607954E56CD46DE85F4F3EF4CC713CC2B95000FA741998558D268', + NetworkType.MIJIN_TEST + ), + [new Mosaic(new NamespaceId('cat.currency'), UInt64.fromUint(10000000))], + PlainMessage.create('Welcome to NEM!'), + NetworkType.MIJIN_TEST + ); + + // Act: + const requestTx = new TransactionQR(transfer, NetworkType.TEST_NET, ''); + const actualJSON = requestTx.toJSON(); + const actualObject = JSON.parse(actualJSON); + + // Assert: + expect(actualObject).to.have.property('v'); + expect(actualObject).to.have.property('type'); + expect(actualObject).to.have.property('network_id'); + expect(actualObject).to.have.property('chain_id'); + expect(actualObject).to.have.property('data'); + }); + }); + +});