Comparing version 1.2.0 to 2.0.0
const cdigit = require('cdigit'); | ||
// Generate and validate check digits using Luhn algorithm | ||
console.log(cdigit.luhn.generate('1234')); // '4' | ||
console.log(cdigit.luhn.encode('1234')); // '12344' | ||
// Luhn algorithm | ||
console.log(cdigit.luhn.compute('1234')); // '4' | ||
console.log(cdigit.luhn.generate('1234')); // '12344' | ||
console.log(cdigit.luhn.validate('12344')); // true | ||
console.log(cdigit.luhn.validate('12345')); // false | ||
// Generate and validate check digits using Verhoeff algorithm | ||
console.log(cdigit.verhoeff.generate('1234')); // '0' | ||
console.log(cdigit.verhoeff.encode('1234')); // '12340' | ||
// Verhoeff algorithm | ||
console.log(cdigit.verhoeff.compute('1234')); // '0' | ||
console.log(cdigit.verhoeff.generate('1234')); // '12340' | ||
console.log(cdigit.verhoeff.validate('12340')); // true | ||
console.log(cdigit.verhoeff.validate('12345')); // false | ||
// ISO/IEC 7064, MOD 11-2 algorithm | ||
console.log(cdigit.mod11_2.compute('1234')); // '4' | ||
console.log(cdigit.mod11_2.generate('1234')); // '12344' | ||
console.log(cdigit.mod11_2.validate('12344')); // true | ||
console.log(cdigit.mod11_2.validate('12345')); // false | ||
// ISO/IEC 7064, MOD 37-2 algorithm | ||
console.log(cdigit.mod37_2.compute('12CD')); // '6' | ||
console.log(cdigit.mod37_2.generate('12CD')); // '12CD6' | ||
console.log(cdigit.mod37_2.validate('12CD6')); // true | ||
console.log(cdigit.mod37_2.validate('12CD5')); // false | ||
// ISO/IEC 7064, MOD 97-10 algorithm | ||
console.log(cdigit.mod97_10.compute('1234')); // '82' | ||
console.log(cdigit.mod97_10.generate('1234')); // '123482' | ||
console.log(cdigit.mod97_10.validate('123482')); // true | ||
console.log(cdigit.mod97_10.validate('123456')); // false | ||
// ISO/IEC 7064, MOD 661-26 algorithm | ||
console.log(cdigit.mod661_26.compute('ABCD')); // 'KN' | ||
console.log(cdigit.mod661_26.generate('ABCD')); // 'ABCDKN' | ||
console.log(cdigit.mod661_26.validate('ABCDKN')); // true | ||
console.log(cdigit.mod661_26.validate('ABCDEF')); // false | ||
// ISO/IEC 7064, MOD 1271-36 algorithm | ||
console.log(cdigit.mod1271_36.compute('12CD')); // 'JU' | ||
console.log(cdigit.mod1271_36.generate('12CD')); // '12CDJU' | ||
console.log(cdigit.mod1271_36.validate('12CDJU')); // true | ||
console.log(cdigit.mod1271_36.validate('12CD56')); // false | ||
// ISO/IEC 7064, MOD 11-10 algorithm | ||
console.log(cdigit.mod11_10.compute('1234')); // '0' | ||
console.log(cdigit.mod11_10.generate('1234')); // '12340' | ||
console.log(cdigit.mod11_10.validate('12340')); // true | ||
console.log(cdigit.mod11_10.validate('12345')); // false | ||
// ISO/IEC 7064, MOD 27-26 algorithm | ||
console.log(cdigit.mod27_26.compute('ABCD')); // 'R' | ||
console.log(cdigit.mod27_26.generate('ABCD')); // 'ABCDR' | ||
console.log(cdigit.mod27_26.validate('ABCDR')); // true | ||
console.log(cdigit.mod27_26.validate('ABCDE')); // false | ||
// ISO/IEC 7064, MOD 37-36 algorithm | ||
console.log(cdigit.mod37_36.compute('12CD')); // '5' | ||
console.log(cdigit.mod37_36.generate('12CD')); // '12CD5' | ||
console.log(cdigit.mod37_36.validate('12CD5')); // true | ||
console.log(cdigit.mod37_36.validate('12CDE')); // false |
@@ -1,10 +0,47 @@ | ||
export default abstract class CdigitAlgo { | ||
/*** Generate a check digit for a number. */ | ||
abstract generate(num: string): string; | ||
/*** Return a combined string of a number and its check digit. */ | ||
encode(num: string): string; | ||
/*** Split a code into a pair of number and check digit. */ | ||
decode(code: string): [string, string]; | ||
/*** Return true if a code or a pair of number and check digit is valid. */ | ||
validate(codeOrNum: string, checkdigit?: string): boolean; | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
/** Common interface for check digit algorithm implementations. */ | ||
export interface Algo { | ||
/** | ||
* Generate a valid number string from a given source number. The generated | ||
* string includes the check digit(s) computed and placed in accordance with | ||
* the algorithm. | ||
*/ | ||
generate(num: string): string; | ||
/** | ||
* Check if a given string is valid in accordance with the algorithm. The | ||
* argument must include check digit(s) as well as the source number. | ||
*/ | ||
validate(num: string): boolean; | ||
/** | ||
* Generate check digit(s) from a given source number. This returns the check | ||
* digit(s) only. | ||
*/ | ||
compute(num: string): string; | ||
/** Split a number into its source number and check digits. */ | ||
parse(num: string): [string, string]; | ||
} | ||
declare type CharMap = { | ||
input: { | ||
[key: string]: number; | ||
}; | ||
output: string; | ||
}; | ||
export declare const helper: { | ||
parseTail: (num: string, n: number) => [string, string]; | ||
iso7064: { | ||
numeric: string; | ||
alphabetic: string; | ||
alphanumeric: string; | ||
compileCharMap: (alphabet: string) => CharMap; | ||
/** Implement ISO 7064 pure system recursive method. */ | ||
computePure: (num: string, mod: number, radix: number, hasTwoCCs: boolean, { output, input }: CharMap) => string; | ||
/** Implement ISO 7064 hybrid system recursive method. */ | ||
computeHybrid: (ds: string, { output, input }: CharMap) => string; | ||
}; | ||
}; | ||
export {}; |
"use strict"; | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
class CdigitAlgo { | ||
/*** Return a combined string of a number and its check digit. */ | ||
encode(num) { | ||
num = String(num); | ||
return num + this.generate(num); | ||
} | ||
/*** Split a code into a pair of number and check digit. */ | ||
decode(code) { | ||
code = String(code); | ||
return [code.slice(0, -1), code.slice(-1)]; | ||
} | ||
/*** Return true if a code or a pair of number and check digit is valid. */ | ||
validate(codeOrNum, checkdigit = '') { | ||
let num = String(codeOrNum); | ||
if (checkdigit === '') { | ||
[num, checkdigit] = this.decode(num); | ||
} | ||
return this.generate(num) === String(checkdigit); | ||
} | ||
} | ||
exports.default = CdigitAlgo; | ||
exports.helper = { | ||
parseTail: (num, n) => { | ||
const ds = String(num); | ||
return [ds.slice(0, -n), ds.slice(-n)]; | ||
}, | ||
iso7064: { | ||
numeric: '0123456789X', | ||
alphabetic: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', | ||
alphanumeric: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*', | ||
compileCharMap: (alphabet) => { | ||
const inv = {}; | ||
for (let i = 0, len = alphabet.length; i < len; i += 1) { | ||
inv[alphabet[i]] = i; | ||
} | ||
return { input: inv, output: alphabet }; | ||
}, | ||
/** Implement ISO 7064 pure system recursive method. */ | ||
computePure: (num, mod, radix, hasTwoCCs, { output, input }) => { | ||
const ds = `${num}${output[0].repeat(hasTwoCCs ? 2 : 1)}`; | ||
const overflowProtection = Math.floor(0xffffffffffff / radix); | ||
let c = 0; | ||
for (let i = 0, len = ds.length; i < len; i += 1) { | ||
c = (c * radix) + input[ds[i]]; | ||
if (c > overflowProtection) { | ||
c %= mod; | ||
} | ||
} | ||
c = (mod + 1 - c % mod) % mod; | ||
if (hasTwoCCs) { | ||
return `${output[Math.floor(c / radix)]}${output[c % radix]}`; | ||
} | ||
return output[c]; | ||
}, | ||
/** Implement ISO 7064 hybrid system recursive method. */ | ||
computeHybrid: (ds, { output, input }) => { | ||
const mod = output.length; | ||
let c = mod; | ||
for (let i = 0, len = ds.length; i < len; i += 1) { | ||
c = (c % (mod + 1)) + input[ds[i]]; | ||
c = (c % mod || mod) * 2; | ||
} | ||
c %= mod + 1; | ||
return output[(mod + 1 - c) % mod]; | ||
}, | ||
}, | ||
}; |
@@ -1,7 +0,15 @@ | ||
declare const _default: { | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
import { Algo } from './common'; | ||
declare class Luhn implements Algo { | ||
compute(num: string): string; | ||
generate(num: string): string; | ||
encode(num: string): string; | ||
decode(code: string): [string, string]; | ||
validate(codeOrNum: string, checkdigit?: string): boolean; | ||
}; | ||
validate(num: string): boolean; | ||
parse(num: string): [string, string]; | ||
} | ||
declare const _default: Luhn; | ||
export default _default; |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const common_1 = require("./common"); | ||
const oddLookup = { | ||
0: 0, 1: 2, 2: 4, 3: 6, 4: 8, 5: 1, 6: 3, 7: 5, 8: 7, 9: 9, | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const common_1 = __importDefault(require("./common")); | ||
const LUHN_ODD_LOOKUP = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]; | ||
exports.default = new class Luhn extends common_1.default { | ||
generate(num) { | ||
num = String(num); | ||
class Luhn { | ||
compute(num) { | ||
const ds = String(num).replace(/[^0-9]/g, ''); | ||
let sum = 0; | ||
for (let i = num.length - 1; i > -1; i -= 2) { // "odd" digits | ||
sum += LUHN_ODD_LOOKUP[Number(num[i])]; | ||
let odd = 1; | ||
for (let i = ds.length - 1; i > -1; i -= 1) { | ||
sum += odd ? oddLookup[ds[i]] : Number(ds[i]); | ||
odd ^= 1; | ||
if (sum > 0xffffffffffff) { // ~2^48 at max | ||
sum %= 10; | ||
} | ||
} | ||
for (let i = num.length - 2; i > -1; i -= 2) { // "even" digits | ||
sum += Number(num[i]); | ||
} | ||
return String(10 - sum % 10).slice(-1); | ||
} | ||
}; | ||
generate(num) { | ||
return `${num}${this.compute(num)}`; | ||
} | ||
validate(num) { | ||
const [src, cc] = this.parse(num); | ||
return this.compute(src) === cc; | ||
} | ||
parse(num) { | ||
return common_1.helper.parseTail(num, 1); | ||
} | ||
} | ||
exports.default = new Luhn(); |
@@ -1,7 +0,15 @@ | ||
declare const _default: { | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
import { Algo } from './common'; | ||
declare class Mod97_10 implements Algo { | ||
compute(num: string): string; | ||
generate(num: string): string; | ||
decode(code: string): [string, string]; | ||
encode(num: string): string; | ||
validate(codeOrNum: string, checkdigit?: string): boolean; | ||
}; | ||
validate(num: string): boolean; | ||
parse(num: string): [string, string]; | ||
} | ||
declare const _default: Mod97_10; | ||
export default _default; |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const common_1 = __importDefault(require("./common")); | ||
const alphabet = ((ds) => { | ||
const map = {}; | ||
for (let i = 0; i < ds.length; ++i) { | ||
map[ds[i]] = String(i); | ||
const common_1 = require("./common"); | ||
class Mod97_10 { | ||
compute(num) { | ||
const ds = `${String(num).replace(/[^0-9]/g, '')}00`; | ||
// Simplified procedure as described in ISO/IEC 7064 | ||
let c = Number(ds.slice(0, 14)) % 97; // 10^14 < 2^48 | ||
for (let i = 14, len = ds.length; i < len; i += 12) { | ||
c = Number(String(c) + ds.slice(i, i + 12)) % 97; | ||
} | ||
return `0${(98 - c) % 97}`.slice(-2); | ||
} | ||
return map; | ||
})('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'); | ||
exports.default = new class Mod97_10 extends common_1.default { | ||
generate(num) { | ||
num = String(num) + '00'; | ||
let base10 = ''; | ||
for (const c of num) { | ||
base10 += alphabet[c]; | ||
} | ||
let c = Number(base10.slice(0, 9)) % 97; | ||
for (let i = 9, len = base10.length; i < len; i += 7) { | ||
c = Number(String(c) + base10.slice(i, i + 7)) % 97; | ||
} | ||
return ('0' + String(98 - c)).slice(-2); | ||
return `${num}${this.compute(num)}`; | ||
} | ||
decode(code) { | ||
code = String(code); | ||
return [code.slice(0, -2), code.slice(-2)]; | ||
validate(num) { | ||
const [src, cc] = this.parse(num); | ||
return this.compute(src) === cc; | ||
} | ||
}; | ||
parse(num) { | ||
return common_1.helper.parseTail(num, 2); | ||
} | ||
} | ||
exports.default = new Mod97_10(); |
@@ -1,7 +0,15 @@ | ||
declare const _default: { | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
import { Algo } from './common'; | ||
declare class Verhoeff implements Algo { | ||
compute(num: string): string; | ||
generate(num: string): string; | ||
encode(num: string): string; | ||
decode(code: string): [string, string]; | ||
validate(codeOrNum: string, checkdigit?: string): boolean; | ||
}; | ||
validate(num: string): boolean; | ||
parse(num: string): [string, string]; | ||
} | ||
declare const _default: Verhoeff; | ||
export default _default; |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const common_1 = __importDefault(require("./common")); | ||
/*** Verhoeff multiplication table */ | ||
const common_1 = require("./common"); | ||
/** Verhoeff multiplication table */ | ||
const d = [ | ||
@@ -20,3 +23,3 @@ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], | ||
]; | ||
/*** Verhoeff permutation table */ | ||
/** Verhoeff permutation table */ | ||
const p = [ | ||
@@ -32,13 +35,24 @@ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], | ||
]; | ||
/*** Verhoeff inverse table */ | ||
/** Verhoeff inverse table */ | ||
const inv = ['0', '4', '3', '2', '1', '5', '6', '7', '8', '9']; | ||
exports.default = new class Verhoeff extends common_1.default { | ||
generate(num) { | ||
num = String(num) + '0'; | ||
class Verhoeff { | ||
compute(num) { | ||
const ds = `${String(num).replace(/[^0-9]/g, '')}0`; | ||
let c = 0; | ||
for (let i = 0, len = num.length; i < len; ++i) { | ||
c = d[c][p[i & 7][Number(num[len - i - 1])]]; | ||
for (let i = 0, len = ds.length; i < len; i += 1) { | ||
c = d[c][p[i & 7][Number(ds[len - i - 1])]]; | ||
} | ||
return inv[c]; | ||
} | ||
}; | ||
generate(num) { | ||
return `${num}${this.compute(num)}`; | ||
} | ||
validate(num) { | ||
const [src, cc] = this.parse(num); | ||
return this.compute(src) === cc; | ||
} | ||
parse(num) { | ||
return common_1.helper.parseTail(num, 1); | ||
} | ||
} | ||
exports.default = new Verhoeff(); |
@@ -0,3 +1,16 @@ | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
export { default as luhn } from './algo/luhn'; | ||
export { default as verhoeff } from './algo/verhoeff'; | ||
export { default as mod11_2 } from './algo/mod11_2'; | ||
export { default as mod37_2 } from './algo/mod37_2'; | ||
export { default as mod97_10 } from './algo/mod97_10'; | ||
export { default as verhoeff } from './algo/verhoeff'; | ||
export { default as mod661_26 } from './algo/mod661_26'; | ||
export { default as mod1271_36 } from './algo/mod1271_36'; | ||
export { default as mod11_10 } from './algo/mod11_10'; | ||
export { default as mod27_26 } from './algo/mod27_26'; | ||
export { default as mod37_36 } from './algo/mod37_36'; |
"use strict"; | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// Popular generic algorithms | ||
var luhn_1 = require("./algo/luhn"); | ||
exports.luhn = luhn_1.default; | ||
var verhoeff_1 = require("./algo/verhoeff"); | ||
exports.verhoeff = verhoeff_1.default; | ||
// ISO/IEC 7064:2003, Pure systems | ||
var mod11_2_1 = require("./algo/mod11_2"); | ||
exports.mod11_2 = mod11_2_1.default; | ||
var mod37_2_1 = require("./algo/mod37_2"); | ||
exports.mod37_2 = mod37_2_1.default; | ||
var mod97_10_1 = require("./algo/mod97_10"); | ||
exports.mod97_10 = mod97_10_1.default; | ||
var verhoeff_1 = require("./algo/verhoeff"); | ||
exports.verhoeff = verhoeff_1.default; | ||
var mod661_26_1 = require("./algo/mod661_26"); | ||
exports.mod661_26 = mod661_26_1.default; | ||
var mod1271_36_1 = require("./algo/mod1271_36"); | ||
exports.mod1271_36 = mod1271_36_1.default; | ||
// ISO/IEC 7064:2003, Hybrid systems | ||
var mod11_10_1 = require("./algo/mod11_10"); | ||
exports.mod11_10 = mod11_10_1.default; | ||
var mod27_26_1 = require("./algo/mod27_26"); | ||
exports.mod27_26 = mod27_26_1.default; | ||
var mod37_36_1 = require("./algo/mod37_36"); | ||
exports.mod37_36 = mod37_36_1.default; |
{ | ||
"name": "cdigit", | ||
"version": "1.2.0", | ||
"description": "Generate and validate check digits", | ||
"version": "2.0.0", | ||
"description": "Collection of check digit algorithms implemented in JavaScript", | ||
"main": "lib/index.js", | ||
@@ -9,4 +9,5 @@ "types": "lib/index.d.ts", | ||
"build": "tsc", | ||
"prepare": "npm run build && npm test", | ||
"test": "mocha" | ||
"prepare": "npm run tslint && npm run build && npm test", | ||
"test": "mocha", | ||
"tslint": "tslint -p package.json" | ||
}, | ||
@@ -19,11 +20,18 @@ "repository": { | ||
"checkdigit", | ||
"check digit", | ||
"algorithm", | ||
"check digit algorithm", | ||
"check character system", | ||
"luhn", | ||
"modulus 10", | ||
"mod 10", | ||
"verhoeff", | ||
"iso7064", | ||
"mod 97", | ||
"iso/iec 7064", | ||
"mod 11-2", | ||
"mod 37-2", | ||
"mod 97-10", | ||
"verhoeff" | ||
"mod 661-26", | ||
"mod 1271-36", | ||
"mod 11-10", | ||
"mod 27-26", | ||
"mod 37-36", | ||
"mod 10", | ||
"mod 97" | ||
], | ||
@@ -44,4 +52,7 @@ "author": "LiosK <contact@mail.liosk.net>", | ||
"mocha": "^5.2.0", | ||
"tslint": "^5.11.0", | ||
"tslint-config-airbnb": "^5.11.1", | ||
"tsutils": "^3.5.0", | ||
"typescript": "^3.1.6" | ||
} | ||
} |
@@ -1,5 +0,6 @@ | ||
# cdigit | ||
# NAME | ||
Generate and validate check digits | ||
cdigit - Collection of check digit algorithms implemented in JavaScript | ||
# SYNOPSIS | ||
@@ -10,13 +11,89 @@ | ||
// Generate and validate check digits using Luhn algorithm | ||
console.log(cdigit.luhn.generate('1234')); // '4' | ||
console.log(cdigit.luhn.encode('1234')); // '12344' | ||
// Luhn (a.k.a. Mod 10) algorithm | ||
console.log(cdigit.luhn.compute('1234')); // '4' | ||
console.log(cdigit.luhn.generate('1234')); // '12344' | ||
console.log(cdigit.luhn.validate('12344')); // true | ||
console.log(cdigit.luhn.validate('12345')); // false | ||
``` | ||
// Generate and validate check digits using Verhoeff algorithm | ||
console.log(cdigit.verhoeff.generate('1234')); // '0' | ||
console.log(cdigit.verhoeff.encode('1234')); // '12340' | ||
console.log(cdigit.verhoeff.validate('12340')); // true | ||
console.log(cdigit.verhoeff.validate('12345')); // false | ||
# SUPPORTED ALGORITHMS | ||
| Algorithm | cdigit name | Input string | Check character(s) | | ||
|---------------------------|-------------|-----------------------|-------------------------------------| | ||
| Luhn | luhn | Numeric (0-9) | 1 digit (0-9) | | ||
| Verhoeff | verhoeff | Numeric (0-9) | 1 digit (0-9) | | ||
| ISO/IEC 7064, MOD 11-2 | mod11_2 | Numeric (0-9) | 1 digit or 'X' (0-9X) | | ||
| ISO/IEC 7064, MOD 37-2 | mod37_2 | Alphanumeric (0-9A-Z) | 1 digit, letter, or '\*' (0-9A-Z\*) | | ||
| ISO/IEC 7064, MOD 97-10 | mod97_10 | Numeric (0-9) | 2 digits (0-9) | | ||
| ISO/IEC 7064, MOD 661-26 | mod661_26 | Alphabetic (A-Z) | 2 letters (A-Z) | | ||
| ISO/IEC 7064, MOD 1271-36 | mod1271_36 | Alphanumeric (0-9A-Z) | 2 digits or letters (0-9A-Z) | | ||
| ISO/IEC 7064, MOD 11-10 | mod11_10 | Numeric (0-9) | 1 digit (0-9) | | ||
| ISO/IEC 7064, MOD 27-26 | mod27_26 | Alphabetic (A-Z) | 1 letter (A-Z) | | ||
| ISO/IEC 7064, MOD 37-36 | mod37_36 | Alphanumeric (0-9A-Z) | 1 digit or letter (0-9A-Z) | | ||
# USAGE | ||
Load `cdigit` and access to an algorithm object by cdigit.*name* as listed in | ||
[SUPPORTED ALGORITHMS section](#supported-algorithms). | ||
```javascript | ||
const cdigit = require('cdigit'); | ||
const algo = cdigit.mod97_10; | ||
``` | ||
Algorithm objects implement the following methods. | ||
## validate(num: string): boolean | ||
Check if a given string is valid in accordance with the algorithm. The argument | ||
must include check digit(s) as well as the source number. | ||
```javascript | ||
console.log(cdigit.mod97_10.validate('123482')); // true | ||
``` | ||
## generate(num: string): string | ||
Generate a valid number string from a given source number. The generated string | ||
includes the check digit(s) computed and placed in accordance with the | ||
algorithm. | ||
```javascript | ||
console.log(cdigit.mod97_10.generate('1234')); // '123482' | ||
``` | ||
## compute(num: string): string | ||
Generate check digit(s) from a given source number. This returns the check | ||
digit(s) only. | ||
```javascript | ||
console.log(cdigit.mod97_10.compute('1234')); // '82' | ||
``` | ||
See [example.js](example.js) for usage examples. | ||
# LICENSE | ||
Copyright (c) 2018 LiosK | ||
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. | ||
# SEE ALSO | ||
* [ISO/IEC 7064:2003](https://www.iso.org/standard/31531.html) | ||
* [GitHub Repository](https://github.com/LiosK/cdigit) | ||
* [npm Package](https://www.npmjs.com/package/cdigit) |
@@ -1,25 +0,87 @@ | ||
export default abstract class CdigitAlgo { | ||
/*** Generate a check digit for a number. */ | ||
abstract generate(num: string): string; | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
/*** Return a combined string of a number and its check digit. */ | ||
encode(num: string): string { | ||
num = String(num); | ||
return num + this.generate(num); | ||
} | ||
/** Common interface for check digit algorithm implementations. */ | ||
export interface Algo { | ||
/** | ||
* Generate a valid number string from a given source number. The generated | ||
* string includes the check digit(s) computed and placed in accordance with | ||
* the algorithm. | ||
*/ | ||
generate(num: string): string; | ||
/*** Split a code into a pair of number and check digit. */ | ||
decode(code: string): [string, string] { | ||
code = String(code); | ||
return [code.slice(0, -1), code.slice(-1)]; | ||
} | ||
/** | ||
* Check if a given string is valid in accordance with the algorithm. The | ||
* argument must include check digit(s) as well as the source number. | ||
*/ | ||
validate(num: string): boolean; | ||
/*** Return true if a code or a pair of number and check digit is valid. */ | ||
validate(codeOrNum: string, checkdigit: string = ''): boolean { | ||
let num = String(codeOrNum); | ||
if (checkdigit === '') { | ||
[num, checkdigit] = this.decode(num); | ||
} | ||
return this.generate(num) === String(checkdigit); | ||
} | ||
/** | ||
* Generate check digit(s) from a given source number. This returns the check | ||
* digit(s) only. | ||
*/ | ||
compute(num: string): string; | ||
/** Split a number into its source number and check digits. */ | ||
parse(num: string): [string, string]; | ||
} | ||
type CharMap = { input: {[key: string]: number}, output: string }; | ||
export const helper = { | ||
parseTail: (num: string, n: number): [string, string] => { | ||
const ds = String(num); | ||
return [ds.slice(0, -n), ds.slice(-n)]; | ||
}, | ||
iso7064: { | ||
numeric: '0123456789X', | ||
alphabetic: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', | ||
alphanumeric: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*', | ||
compileCharMap: (alphabet: string): CharMap => { | ||
const inv: {[key: string]: number} = {}; | ||
for (let i = 0, len = alphabet.length; i < len; i += 1) { | ||
inv[alphabet[i]] = i; | ||
} | ||
return { input: inv, output: alphabet }; | ||
}, | ||
/** Implement ISO 7064 pure system recursive method. */ | ||
computePure: ( | ||
num: string, mod: number, radix: number, | ||
hasTwoCCs: boolean, { output, input }: CharMap, | ||
) => { | ||
const ds = `${num}${output[0].repeat(hasTwoCCs ? 2 : 1)}`; | ||
const overflowProtection = Math.floor(0xffffffffffff / radix); | ||
let c = 0; | ||
for (let i = 0, len = ds.length; i < len; i += 1) { | ||
c = (c * radix) + input[ds[i]]; | ||
if (c > overflowProtection) { | ||
c %= mod; | ||
} | ||
} | ||
c = (mod + 1 - c % mod) % mod; | ||
if (hasTwoCCs) { | ||
return `${output[Math.floor(c / radix)]}${output[c % radix]}`; | ||
} | ||
return output[c]; | ||
}, | ||
/** Implement ISO 7064 hybrid system recursive method. */ | ||
computeHybrid: (ds: string, { output, input }: CharMap) => { | ||
const mod = output.length; | ||
let c = mod; | ||
for (let i = 0, len = ds.length; i < len; i += 1) { | ||
c = (c % (mod + 1)) + input[ds[i]]; | ||
c = (c % mod || mod) * 2; | ||
} | ||
c %= mod + 1; | ||
return output[(mod + 1 - c) % mod]; | ||
}, | ||
}, | ||
}; |
@@ -1,19 +0,45 @@ | ||
import CdigitAlgo from './common'; | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
const LUHN_ODD_LOOKUP = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]; | ||
import { Algo, helper } from './common'; | ||
export default new class Luhn extends CdigitAlgo { | ||
generate(num: string): string { | ||
num = String(num); | ||
const oddLookup: {[key: string]: number} = { | ||
0: 0, 1: 2, 2: 4, 3: 6, 4: 8, 5: 1, 6: 3, 7: 5, 8: 7, 9: 9, | ||
}; | ||
class Luhn implements Algo { | ||
compute(num: string): string { | ||
const ds = String(num).replace(/[^0-9]/g, ''); | ||
let sum = 0; | ||
for (let i = num.length - 1; i > -1; i -= 2) { // "odd" digits | ||
sum += LUHN_ODD_LOOKUP[Number(num[i])]; | ||
let odd = 1; | ||
for (let i = ds.length - 1; i > -1; i -= 1) { | ||
sum += odd ? oddLookup[ds[i]] : Number(ds[i]); | ||
odd ^= 1; | ||
if (sum > 0xffffffffffff) { // ~2^48 at max | ||
sum %= 10; | ||
} | ||
} | ||
for (let i = num.length - 2; i > -1; i -= 2) { // "even" digits | ||
sum += Number(num[i]); | ||
} | ||
return String(10 - sum % 10).slice(-1); | ||
} | ||
generate(num: string): string { | ||
return `${num}${this.compute(num)}`; | ||
} | ||
validate(num: string): boolean { | ||
const [src, cc] = this.parse(num); | ||
return this.compute(src) === cc; | ||
} | ||
parse(num: string): [string, string] { | ||
return helper.parseTail(num, 1); | ||
} | ||
} | ||
export default new Luhn(); |
@@ -1,32 +0,37 @@ | ||
import CdigitAlgo from './common'; | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
const alphabet = ((ds) => { | ||
const map: {[key: string]: string} = {}; | ||
for (let i = 0; i < ds.length; ++i) { | ||
map[ds[i]] = String(i); | ||
} | ||
return map; | ||
})('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'); | ||
import { Algo, helper } from './common'; | ||
export default new class Mod97_10 extends CdigitAlgo { | ||
generate(num: string): string { | ||
num = String(num) + '00'; | ||
class Mod97_10 implements Algo { | ||
compute(num: string): string { | ||
const ds = `${String(num).replace(/[^0-9]/g, '')}00`; | ||
let base10 = ''; | ||
for (const c of num) { | ||
base10 += alphabet[c]; | ||
// Simplified procedure as described in ISO/IEC 7064 | ||
let c = Number(ds.slice(0, 14)) % 97; // 10^14 < 2^48 | ||
for (let i = 14, len = ds.length; i < len; i += 12) { | ||
c = Number(String(c) + ds.slice(i, i + 12)) % 97; | ||
} | ||
let c = Number(base10.slice(0, 9)) % 97; | ||
for (let i = 9, len = base10.length; i < len; i += 7) { | ||
c = Number(String(c) + base10.slice(i, i + 7)) % 97; | ||
} | ||
return `0${(98 - c) % 97}`.slice(-2); | ||
} | ||
return ('0' + String(98 - c)).slice(-2); | ||
generate(num: string): string { | ||
return `${num}${this.compute(num)}`; | ||
} | ||
decode(code: string): [string, string] { | ||
code = String(code); | ||
return [code.slice(0, -2), code.slice(-2)]; | ||
validate(num: string): boolean { | ||
const [src, cc] = this.parse(num); | ||
return this.compute(src) === cc; | ||
} | ||
parse(num: string): [string, string] { | ||
return helper.parseTail(num, 2); | ||
} | ||
} | ||
export default new Mod97_10(); |
@@ -1,4 +0,11 @@ | ||
import CdigitAlgo from './common'; | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
/*** Verhoeff multiplication table */ | ||
import { Algo, helper } from './common'; | ||
/** Verhoeff multiplication table */ | ||
const d = [ | ||
@@ -17,3 +24,3 @@ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], | ||
/*** Verhoeff permutation table */ | ||
/** Verhoeff permutation table */ | ||
const p = [ | ||
@@ -30,12 +37,12 @@ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], | ||
/*** Verhoeff inverse table */ | ||
/** Verhoeff inverse table */ | ||
const inv = ['0', '4', '3', '2', '1', '5', '6', '7', '8', '9']; | ||
export default new class Verhoeff extends CdigitAlgo { | ||
generate(num: string): string { | ||
num = String(num) + '0'; | ||
class Verhoeff implements Algo { | ||
compute(num: string): string { | ||
const ds = `${String(num).replace(/[^0-9]/g, '')}0`; | ||
let c = 0; | ||
for (let i = 0, len = num.length; i < len; ++i) { | ||
c = d[c][p[i & 7][Number(num[len - i - 1])]]; | ||
for (let i = 0, len = ds.length; i < len; i += 1) { | ||
c = d[c][p[i & 7][Number(ds[len - i - 1])]]; | ||
} | ||
@@ -45,2 +52,17 @@ | ||
} | ||
generate(num: string): string { | ||
return `${num}${this.compute(num)}`; | ||
} | ||
validate(num: string): boolean { | ||
const [src, cc] = this.parse(num); | ||
return this.compute(src) === cc; | ||
} | ||
parse(num: string): [string, string] { | ||
return helper.parseTail(num, 1); | ||
} | ||
} | ||
export default new Verhoeff(); |
@@ -0,3 +1,22 @@ | ||
/** | ||
* cdigit | ||
* | ||
* @copyright 2018 LiosK | ||
* @license Apache-2.0 | ||
*/ | ||
// Popular generic algorithms | ||
export { default as luhn } from './algo/luhn'; | ||
export { default as verhoeff } from './algo/verhoeff'; | ||
// ISO/IEC 7064:2003, Pure systems | ||
export { default as mod11_2 } from './algo/mod11_2'; | ||
export { default as mod37_2 } from './algo/mod37_2'; | ||
export { default as mod97_10 } from './algo/mod97_10'; | ||
export { default as verhoeff } from './algo/verhoeff'; | ||
export { default as mod661_26 } from './algo/mod661_26'; | ||
export { default as mod1271_36 } from './algo/mod1271_36'; | ||
// ISO/IEC 7064:2003, Hybrid systems | ||
export { default as mod11_10 } from './algo/mod11_10'; | ||
export { default as mod27_26 } from './algo/mod27_26'; | ||
export { default as mod37_36 } from './algo/mod37_36'; |
501
test/luhn.js
@@ -0,187 +1,346 @@ | ||
'use strict'; | ||
const assert = require('assert').strict; | ||
const cdigit = require('..'); | ||
const common = require('./common'); | ||
const algo = require('..').luhn; | ||
describe('Luhn algorithm', () => { | ||
const name = 'luhn'; | ||
const algo = cdigit[name]; | ||
// {{{ List sample strings | ||
const valid = [ | ||
['639283842', '8'], ['612168805', '2'], | ||
['924800170', '4'], ['427176307', '2'], | ||
['916912504', '5'], ['385833974', '4'], | ||
['603976130', '6'], ['788414730', '2'], | ||
]; | ||
// short cases | ||
['6392838428', '639283842', '8'], | ||
['6121688052', '612168805', '2'], | ||
['9248001704', '924800170', '4'], | ||
['4271763072', '427176307', '2'], | ||
['9169125045', '916912504', '5'], | ||
['3858339744', '385833974', '4'], | ||
['6039761306', '603976130', '6'], | ||
['7884147302', '788414730', '2'], | ||
const invalid = [ | ||
['639283842', '1'], ['612168805', '9'], | ||
['924800170', '7'], ['427176307', '5'], | ||
['916912504', '2'], ['385833974', '5'], | ||
['603976130', '4'], ['788414730', '1'], | ||
]; | ||
// leading zeros | ||
['006392838428', '00639283842', '8'], | ||
['006121688052', '00612168805', '2'], | ||
['009248001704', '00924800170', '4'], | ||
['004271763072', '00427176307', '2'], | ||
['00009169125045', '0000916912504', '5'], | ||
['00003858339744', '0000385833974', '4'], | ||
['00006039761306', '0000603976130', '6'], | ||
['00007884147302', '0000788414730', '2'], | ||
const large = [ | ||
['337689354611811278911584191118941269108603765', '0'], | ||
['425818470785860807265159197745905287403180971', '5'], | ||
['564102520726223698305625859271932637683426856', '5'], | ||
['578979745902582135441775638253369716621004051', '2'], | ||
]; | ||
// special characters | ||
['6-39-28-38428', '6-39-28-3842', '8'], | ||
['61 216 88 052', '61 216 88 05', '2'], | ||
['X92-4800170ABC4', 'X92-4800170ABC', '4'], | ||
[' 4271 7630 7 2', ' 4271 7630 7 ', '2'], | ||
describe(name + '.generate()', () => { | ||
it('generates a correct check digit', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.equal(algo.generate(num), checkdigit, `${name}.generate(${num})`); | ||
} | ||
}); | ||
// large | ||
['3376893546118112789115841911189412691086037650', '337689354611811278911584191118941269108603765', '0'], | ||
['4258184707858608072651591977459052874031809715', '425818470785860807265159197745905287403180971', '5'], | ||
['5641025207262236983056258592719326376834268565', '564102520726223698305625859271932637683426856', '5'], | ||
['5789797459025821354417756382533697166210040512', '578979745902582135441775638253369716621004051', '2'], | ||
it('is not affected by leading zeros', () => { | ||
for (let [num, checkdigit] of valid) { | ||
num = '0000' + num; | ||
assert.equal(algo.generate(num), checkdigit, `${name}.generate(${num})`); | ||
} | ||
}); | ||
// bulk | ||
['79927398713', '7992739871', '3'], | ||
['49927398716', '4992739871', '6'], | ||
['1234567812345670', '123456781234567', '0'], | ||
['4024007199952671', '402400719995267', '1'], | ||
['4968009448991185', '496800944899118', '5'], | ||
['4485031936696447520', '448503193669644752', '0'], | ||
['2720991026808100', '272099102680810', '0'], | ||
['5313977435287891', '531397743528789', '1'], | ||
['5144122279996944', '514412227999694', '4'], | ||
['345624181492183', '34562418149218', '3'], | ||
['379723913300158', '37972391330015', '8'], | ||
['345999017580637', '34599901758063', '7'], | ||
['6011232699595685', '601123269959568', '5'], | ||
['6011491169622003', '601149116962200', '3'], | ||
['6011285697355763491', '601128569735576349', '1'], | ||
['3542720990091367', '354272099009136', '7'], | ||
['3532233574622997', '353223357462299', '7'], | ||
['3532788220114354666', '353278822011435466', '6'], | ||
['5403399339551671', '540339933955167', '1'], | ||
['5585760385211280', '558576038521128', '0'], | ||
['5481899719102875', '548189971910287', '5'], | ||
['30540557891578', '3054055789157', '8'], | ||
['30071210433038', '3007121043303', '8'], | ||
['30126773590440', '3012677359044', '0'], | ||
['36300226927160', '3630022692716', '0'], | ||
['36462605784370', '3646260578437', '0'], | ||
['36705219593581', '3670521959358', '1'], | ||
['6763637858365987', '676363785836598', '7'], | ||
['6762136018635356', '676213601863535', '6'], | ||
['6762285720444928', '676228572044492', '8'], | ||
['4175003833113538', '417500383311353', '8'], | ||
['4917845148786751', '491784514878675', '1'], | ||
['4508189071154330', '450818907115433', '0'], | ||
['6397642356831336', '639764235683133', '6'], | ||
['6379177784930725', '637917778493072', '5'], | ||
['6371983222326360', '637198322232636', '0'], | ||
['54614881525019073782156187965076037537577', '5461488152501907378215618796507603753757', '7'], | ||
['1980181852120423152985411461523796354096776217426', '198018185212042315298541146152379635409677621742', '6'], | ||
['71103629781953043577711278657782051037', '7110362978195304357771127865778205103', '7'], | ||
['192199918727254420496996509883617', '19219991872725442049699650988361', '7'], | ||
['6516603288299521252958133', '651660328829952125295813', '3'], | ||
['0549698768273073295451997422543678225772666307', '054969876827307329545199742254367822577266630', '7'], | ||
['86495665960757938740047056426450277738', '8649566596075793874004705642645027773', '8'], | ||
['38563081735134959023238795', '3856308173513495902323879', '5'], | ||
['0881396675714293553912574348891', '088139667571429355391257434889', '1'], | ||
['75404226575672', '7540422657567', '2'], | ||
['03847351582239584836738165588731595', '0384735158223958483673816558873159', '5'], | ||
['092078018048435165891915630831222779842123', '09207801804843516589191563083122277984212', '3'], | ||
['83', '8', '3'], | ||
['796664111657831540925156678893534', '79666411165783154092515667889353', '4'], | ||
['083889026416332434227082611', '08388902641633243422708261', '1'], | ||
['7450', '745', '0'], | ||
['8887534935045735788', '888753493504573578', '8'], | ||
['50683991576788465201738584670068', '5068399157678846520173858467006', '8'], | ||
['6300661074658572109235946105681759702222940944358', '630066107465857210923594610568175970222294094435', '8'], | ||
['49597490064422818107761315748561', '4959749006442281810776131574856', '1'], | ||
['08895394941', '0889539494', '1'], | ||
['7885627', '788562', '7'], | ||
['860294917355734824232955794862662219753570727', '86029491735573482423295579486266221975357072', '7'], | ||
['316155958410984136823404028590294859389315', '31615595841098413682340402859029485938931', '5'], | ||
['37127747921881019081390599573226109070772', '3712774792188101908139059957322610907077', '2'], | ||
['8240027262937782385843427698937482724595', '824002726293778238584342769893748272459', '5'], | ||
['563172906064393026806598062505683170605416142', '56317290606439302680659806250568317060541614', '2'], | ||
['323659', '32365', '9'], | ||
['0994905', '099490', '5'], | ||
['09386209765806087018516207', '0938620976580608701851620', '7'], | ||
['33421525854302365772578573973135641848979706', '3342152585430236577257857397313564184897970', '6'], | ||
['29330', '2933', '0'], | ||
['8498596997358554364532632997585040', '849859699735855436453263299758504', '0'], | ||
['8576167814467109832320', '857616781446710983232', '0'], | ||
['232', '23', '2'], | ||
['6324764819359558617790395076257264506616106832933', '632476481935955861779039507625726450661610683293', '3'], | ||
['294120048623149305988437330', '29412004862314930598843733', '0'], | ||
['7900111062867757453184244386710373296814574668', '790011106286775745318424438671037329681457466', '8'], | ||
['5367538500607856908983576772524810945111620762179', '536753850060785690898357677252481094511162076217', '9'], | ||
['968', '96', '8'], | ||
['8961', '896', '1'], | ||
['85370137279014395447', '8537013727901439544', '7'], | ||
['2005169774293', '200516977429', '3'], | ||
['623477229032567', '62347722903256', '7'], | ||
['863862108', '86386210', '8'], | ||
['59646720260211469659151766871919368641', '5964672026021146965915176687191936864', '1'], | ||
['67', '6', '7'], | ||
['45203', '4520', '3'], | ||
['7915744454676547808109853644', '791574445467654780810985364', '4'], | ||
['5875487361106669', '587548736110666', '9'], | ||
['6624140838899141132014247713', '662414083889914113201424771', '3'], | ||
['9756567794897599766290433002294318359', '975656779489759976629043300229431835', '9'], | ||
['72397', '7239', '7'], | ||
['218463818', '21846381', '8'], | ||
['263813770569251323679670745238933084455721', '26381377056925132367967074523893308445572', '1'], | ||
['69734877926', '6973487792', '6'], | ||
['89658158373339137022294', '8965815837333913702229', '4'], | ||
['1552215830', '155221583', '0'], | ||
['76035643643530792048269134', '7603564364353079204826913', '4'], | ||
['338009939', '33800993', '9'], | ||
['018994193005121895596566825490', '01899419300512189559656682549', '0'], | ||
['4581126992476809766513180443332', '458112699247680976651318044333', '2'], | ||
['66786195948495022', '6678619594849502', '2'], | ||
['315121216515975938839', '31512121651597593883', '9'], | ||
['33489890479999623652996047457384625515132870', '3348989047999962365299604745738462551513287', '0'], | ||
['262253938212053138418267398242050268050', '26225393821205313841826739824205026805', '0'], | ||
['52784212', '5278421', '2'], | ||
['1768425892', '176842589', '2'], | ||
['85520518', '8552051', '8'], | ||
['7312557433533855', '731255743353385', '5'], | ||
['34194998730219623', '3419499873021962', '3'], | ||
['25937279309026750', '2593727930902675', '0'], | ||
['41582', '4158', '2'], | ||
['2857', '285', '7'], | ||
['850358582146570426568272360872360087', '85035858214657042656827236087236008', '7'], | ||
['125957343885973496512989716687495', '12595734388597349651298971668749', '5'], | ||
['03044278', '0304427', '8'], | ||
['05108454829869214309740788612171015584', '0510845482986921430974078861217101558', '4'], | ||
['4039079', '403907', '9'], | ||
['80723383033265757759681334', '8072338303326575775968133', '4'], | ||
['75', '7', '5'], | ||
['574199228829400903986384817447646917802011348', '57419922882940090398638481744764691780201134', '8'], | ||
['331', '33', '1'], | ||
['46978507410879403373513', '4697850741087940337351', '3'], | ||
['07731773181451843', '0773177318145184', '3'], | ||
['461907819256261684784230449111038702651', '46190781925626168478423044911103870265', '1'], | ||
['30084558181558765529058899629211451664063802541', '3008455818155876552905889962921145166406380254', '1'], | ||
['663743100507053993899002238074585', '66374310050705399389900223807458', '5'], | ||
['44425446487294639133493226245186890667105856', '4442544648729463913349322624518689066710585', '6'], | ||
['15924932017293097589542466771758', '1592493201729309758954246677175', '8'], | ||
['0585916146334538751506007', '058591614633453875150600', '7'], | ||
['40679114499882976614293849035141192017', '4067911449988297661429384903514119201', '7'], | ||
['519865441544075878870', '51986544154407587887', '0'], | ||
['664810302611584179617892709160140344776901942', '66481030261158417961789270916014034477690194', '2'], | ||
['3511381339378715469366018', '351138133937871546936601', '8'], | ||
['56493816473474509107345480', '5649381647347450910734548', '0'], | ||
['5741555974830965569095742116601699', '574155597483096556909574211660169', '9'], | ||
['36707719368859941969937943', '3670771936885994196993794', '3'], | ||
['028867500681480919786133544924778704076040965', '02886750068148091978613354492477870407604096', '5'], | ||
['22454940441011231356', '2245494044101123135', '6'], | ||
['943', '94', '3'], | ||
['569438271987', '56943827198', '7'], | ||
['613810', '61381', '0'], | ||
['52039872', '5203987', '2'], | ||
['455', '45', '5'], | ||
['3110938967462244116852248333447562947300982', '311093896746224411685224833344756294730098', '2'], | ||
['7799891456854353253', '779989145685435325', '3'], | ||
['0136612850', '013661285', '0'], | ||
['776393540916201734200835839', '77639354091620173420083583', '9'], | ||
['0237247724634033977', '023724772463403397', '7'], | ||
['97042462639560872859475', '9704246263956087285947', '5'], | ||
['88177429762445461368974189093209625050470', '8817742976244546136897418909320962505047', '0'], | ||
['1176165340804266', '117616534080426', '6'], | ||
['4448902861372789129733172264672773151287726440', '444890286137278912973317226467277315128772644', '0'], | ||
['2269082', '226908', '2'], | ||
['06896345684029731903256637529107857206016', '0689634568402973190325663752910785720601', '6'], | ||
['85957928264976', '8595792826497', '6'], | ||
['779107316324250893550133606348025527726', '77910731632425089355013360634802552772', '6'], | ||
['0907504023894713968867734267473401822', '090750402389471396886773426747340182', '2'], | ||
['3859825684349', '385982568434', '9'], | ||
['3177279707927209', '317727970792720', '9'], | ||
['8550406179730333982075', '855040617973033398207', '5'], | ||
['7464449650889249566946524428088716678022357024530', '746444965088924956694652442808871667802235702453', '0'], | ||
['90258743775887828360122408364180133258855663207', '9025874377588782836012240836418013325885566320', '7'], | ||
['0293953975696', '029395397569', '6'], | ||
['6532499716831854673100166936758607468340821272580', '653249971683185467310016693675860746834082127258', '0'], | ||
['7791645920544', '779164592054', '4'], | ||
['3514991100863763983700', '351499110086376398370', '0'], | ||
]; | ||
it('accepts Number type as argument', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.equal(algo.generate(Number(num)), checkdigit, `${name}.generate(${num})`); | ||
} | ||
}); | ||
it('accepts large decimal strings', () => { | ||
for (const [num, checkdigit] of large) { | ||
assert.equal(algo.generate(num), checkdigit, `${name}.generate(${num})`); | ||
} | ||
}); | ||
}); | ||
const invalid = [ | ||
'6392838421', | ||
'6121688059', | ||
'9248001707', | ||
'4271763075', | ||
'9169125042', | ||
'3858339745', | ||
'6039761304', | ||
'7884147301', | ||
'068708067027311981306064527483090583446388', | ||
'3913457462233136864081203885827153721998236091', | ||
'722079608322052231983840357389776026691421092', | ||
'23359723550996', | ||
'028475029020470949485384686', | ||
'246355749714957', | ||
'4686949083', | ||
'093276231', | ||
'710821628420', | ||
'5671431076387547691746', | ||
'25601777009421961189069672471', | ||
'32815824414667935457262391050171012', | ||
'04456', | ||
'7886262331192414', | ||
'310367107146943414636692551774259043131881', | ||
'289002427113785452336380863380016574613336', | ||
'68335020692696657286801982061799684156', | ||
'154192190561376702893127011', | ||
'8515597340', | ||
'71470341208027909882306950054103542239441', | ||
'1574754365300635103670872604555508989627', | ||
'790609521274336907519', | ||
'3586072675653240416886803122465442824090268245840', | ||
'2937', | ||
'63146254', | ||
'02224792606711397534821577025352211741302962202', | ||
'28430750063317550278578633048214089144553', | ||
'4534831978552965164131948281558', | ||
'2967552421510192237347175021197177333878', | ||
'49023821327119191026308305503659982837433', | ||
'458686845182367652447', | ||
'032437937741846045419592880226147', | ||
'87128286132832', | ||
'7866939527758288362301366127142195119167', | ||
'1755614880757414840349021079157897056829284571035', | ||
'461879964439551392955750', | ||
'33', | ||
'187894786712582185137844999592312', | ||
'0292815674511', | ||
'418324473598556718580714594841117688286', | ||
'6272', | ||
'80008696575726384728', | ||
'000016729532868016414001118559770839', | ||
'360356419907268654632604', | ||
'739048752145894665', | ||
'1423914103611333416666209612998650', | ||
'0994618958', | ||
'4403820785298729065165338698', | ||
'0744659779675944211', | ||
'55966517848075', | ||
'892632986026435471277899504432', | ||
'7301', | ||
'5487621816', | ||
'92977122912408192', | ||
'18151904992777567414988', | ||
'374327', | ||
'374816606488036317725043279477071763950', | ||
'49227002639868324784327274354408870', | ||
'97373333824964909826510628632233296', | ||
'9804155099485934209474313', | ||
'3233302764417434734362447170856911985007', | ||
'87741352341391238074', | ||
'7357070142971997455', | ||
'0431014690031680275859', | ||
'598', | ||
'480890076', | ||
'592525', | ||
'5199395361638', | ||
'120716', | ||
'6699701772601879496766124878286054493452289', | ||
'36892701346824', | ||
'5466060712575115076055374531595', | ||
'041310571160011544011', | ||
'9512618487581182', | ||
'8862670494156451158091182778', | ||
'5253089105752163357784515', | ||
'2691928', | ||
'2242', | ||
'0373135119640172593626693567150017713426', | ||
'83717481660424883558059989497310616916', | ||
'13595167800855746', | ||
'087227272', | ||
'696441789221', | ||
'695265198265', | ||
'4501486212254454138460770696213605530982461', | ||
'46066702193683366991748423410275056', | ||
'694093454102806559377836462638205195636301151', | ||
'530831182876', | ||
'911568841692892005475835773913179032', | ||
'4011257213843365315926971016597295136', | ||
'51761921', | ||
'63418011869116970354945464', | ||
'1711430179', | ||
'8610504703682064519863727939045812579646287784097', | ||
'232251867808744015457413166125', | ||
'1767167', | ||
'8711959062521450730101543617102', | ||
'795776853946', | ||
'02390867554521165130979', | ||
'0385252401923660837899675993148080596742', | ||
'474577839', | ||
'40099832017141180543769235774', | ||
'0666451590169073293403139385820982300115526754266', | ||
'52923046652587976731502408971', | ||
'18465756339241354925', | ||
'826836721040094114209229746035668345730015', | ||
'88985702594', | ||
'9053390928432206013675401173744706672448', | ||
'23787271574', | ||
'1673', | ||
'43948910004104045848', | ||
'714', | ||
'323616925438820407103117890111914774624128686', | ||
'48416578105154974401301935165512651979', | ||
]; | ||
// }}} | ||
describe(name + '.validate()', () => { | ||
it('returns true if a code or a pair of number and check digit is valid', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.ok(algo.validate(num + checkdigit), `${name}.validate(${num + checkdigit})`); | ||
assert.ok(algo.validate(num, checkdigit), `${name}.validate(${num}, ${checkdigit})`); | ||
} | ||
}); | ||
it('returns false if a code or a pair of number and check digit is invalid', () => { | ||
for (const [num, checkdigit] of invalid) { | ||
assert.ok(!algo.validate(num + checkdigit), `!${name}.validate(${num + checkdigit})`); | ||
assert.ok(!algo.validate(num, checkdigit), `!${name}.validate(${num}, ${checkdigit})`); | ||
} | ||
}); | ||
common.testAlgo(algo, valid, invalid); | ||
it('is not affected by leading zeros', () => { | ||
for (let [num, checkdigit] of valid) { | ||
num = '0000' + num; | ||
assert.ok(algo.validate(num + checkdigit), `${name}.validate(${num + checkdigit})`); | ||
assert.ok(algo.validate(num, checkdigit), `${name}.validate(${num}, ${checkdigit})`); | ||
} | ||
}); | ||
describe('luhn.validate()', () => { | ||
it('accepts Number type as argument', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.ok(algo.validate(Number(num + checkdigit)), `${name}.validate(${num + checkdigit})`); | ||
assert.ok(algo.validate(Number(num), checkdigit), `${name}.validate(${num}, ${checkdigit})`); | ||
const shortCases = valid.slice(0, 16); | ||
for (const [num, src, cc] of shortCases) { | ||
assert.ok(algo.validate(Number(num)), `validate(Number(${num})`); | ||
} | ||
}); | ||
it('accepts large decimal strings', () => { | ||
for (const [num, checkdigit] of large) { | ||
assert.ok(algo.validate(num + checkdigit), `${name}.validate(${num + checkdigit})`); | ||
assert.ok(algo.validate(num, checkdigit), `${name}.validate(${num}, ${checkdigit})`); | ||
} | ||
}); | ||
}); | ||
}); | ||
describe(name + '.encode()', () => { | ||
it('appends a correct check digit to a number', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.equal(algo.encode(num), num + checkdigit, `${name}.encode(${num})`); | ||
} | ||
}); | ||
it('is not affected by leading zeros', () => { | ||
for (let [num, checkdigit] of valid) { | ||
num = '0000' + num; | ||
assert.equal(algo.encode(num), num + checkdigit, `${name}.encode(${num})`); | ||
} | ||
}); | ||
it('accepts Number type as argument', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.equal(algo.encode(Number(num)), num + checkdigit, `${name}.encode(${num})`); | ||
} | ||
}); | ||
it('accepts large decimal strings', () => { | ||
for (const [num, checkdigit] of large) { | ||
assert.equal(algo.encode(num), num + checkdigit, `${name}.encode(${num})`); | ||
} | ||
}); | ||
}); | ||
describe(name + '.decode()', () => { | ||
it('separates the leading digits and the last digit', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.deepEqual(algo.decode(num + checkdigit), [num, checkdigit], `${name}.decode(${num + checkdigit})`); | ||
} | ||
}); | ||
it('accepts Number type as argument', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.deepEqual(algo.decode(Number(num + checkdigit)), [num, checkdigit], `${name}.decode(${num + checkdigit})`); | ||
} | ||
}); | ||
it('accepts large decimal strings', () => { | ||
for (const [num, checkdigit] of large) { | ||
assert.deepEqual(algo.decode(num + checkdigit), [num, checkdigit], `${name}.decode(${num + checkdigit})`); | ||
} | ||
}); | ||
}); | ||
describe('bulk example test', () => { | ||
const examples = [ | ||
'79927398713', | ||
'49927398716', | ||
'1234567812345670', | ||
'4024007199952671', | ||
'4968009448991185', | ||
'4485031936696447520', | ||
'2720991026808100', | ||
'5313977435287891', | ||
'5144122279996944', | ||
'345624181492183', | ||
'379723913300158', | ||
'345999017580637', | ||
'6011232699595685', | ||
'6011491169622003', | ||
'6011285697355763491', | ||
'3542720990091367', | ||
'3532233574622997', | ||
'3532788220114354666', | ||
'5403399339551671', | ||
'5585760385211280', | ||
'5481899719102875', | ||
'30540557891578', | ||
'30071210433038', | ||
'30126773590440', | ||
'36300226927160', | ||
'36462605784370', | ||
'36705219593581', | ||
'6763637858365987', | ||
'6762136018635356', | ||
'6762285720444928', | ||
'4175003833113538', | ||
'4917845148786751', | ||
'4508189071154330', | ||
'6397642356831336', | ||
'6379177784930725', | ||
'6371983222326360', | ||
]; | ||
it('applies the four functions to collected valid examples', () => { | ||
for (const e of examples) { | ||
const [num, checkdigit] = [e.slice(0, -1), e.slice(-1)]; | ||
assert.equal(algo.generate(num), checkdigit, `${name}.generate(${num})`); | ||
assert.ok(algo.validate(e), `${name}.validate(${e})`); | ||
assert.ok(algo.validate(num, checkdigit), `${name}.validate(${num}, ${checkdigit})`); | ||
assert.equal(algo.encode(num), e, `${name}.encode(${num})`); | ||
assert.deepEqual(algo.decode(e), [num, checkdigit], `${name}.decode(${e})`); | ||
} | ||
}); | ||
}); | ||
}); | ||
// vim: fdm=marker fmr& |
@@ -0,153 +1,341 @@ | ||
'use strict'; | ||
const assert = require('assert').strict; | ||
const cdigit = require('..'); | ||
const common = require('./common'); | ||
const algo = require('..').mod97_10; | ||
describe('ISO/IEC 7064, MOD 97-10 algorithm', () => { | ||
const name = 'mod97_10'; | ||
const algo = cdigit[name]; | ||
// {{{ List sample strings | ||
const valid = [ | ||
['096123456769BE', '71'], | ||
['30006000011234567890189FR', '76'], | ||
['100000000123456789DE', '91'], | ||
['08100010000001234567890GR', '96'], | ||
['BCYP0000001234567890RO', '09'], | ||
['20000001234567891234SA', '44'], | ||
['21000813610123456789ES', '79'], | ||
['04835012345678009CH', '56'], | ||
['MIDL07009312345678GB', '98'], | ||
['79444', '794', '44'], | ||
['3214282912345698765432161182', '32142829123456987654321611', '82'], | ||
['06 000 0123456758', '06 000 01234567', '58'], | ||
['900596501', '9005965', '01'], | ||
['170122496775181', '1701224967751', '81'], | ||
['3376959', '33769', '59'], | ||
['60242803474357254', '602428034743572', '54'], | ||
['24215059340', '242150593', '40'], | ||
['9423073768704', '94230737687', '04'], | ||
['1378759022748795', '13787590227487', '95'], | ||
['554530813969745', '5545308139697', '45'], | ||
['987916871', '9879168', '71'], | ||
['666529550021', '6665295500', '21'], | ||
['53818235782', '538182357', '82'], | ||
['2121292250870', '21212922508', '70'], | ||
['58424016263', '584240162', '63'], | ||
['335757871242', '3357578712', '42'], | ||
['413415', '4134', '15'], | ||
['0000105594942287263', '00001055949422872', '63'], | ||
['173340', '1733', '40'], | ||
['81004507', '810045', '07'], | ||
['0053826116217006944', '00538261162170069', '44'], | ||
['63794371211', '637943712', '11'], | ||
['0085554486', '00855544', '86'], | ||
['055543746716993', '0555437467169', '93'], | ||
['5666963300015', '56669633000', '15'], | ||
['00001278481359660446', '000012784813596604', '46'], | ||
['4034268683601', '40342686836', '01'], | ||
['572692557449', '5726925574', '49'], | ||
['00009913013', '000099130', '13'], | ||
['393074459', '3930744', '59'], | ||
['19919023042', '199190230', '42'], | ||
['8989185', '89891', '85'], | ||
['910852796', '9108527', '96'], | ||
['771074826', '7710748', '26'], | ||
['31066636492', '310666364', '92'], | ||
['00193796793537', '001937967935', '37'], | ||
['35241582347114', '352415823471', '14'], | ||
['06897794549', '068977945', '49'], | ||
['5399794787307', '53997947873', '07'], | ||
['4101258', '41012', '58'], | ||
['798512634', '7985126', '34'], | ||
['94783218575904266', '947832185759042', '66'], | ||
['2509569922100', '25095699221', '00'], | ||
['774148580247517', '7741485802475', '17'], | ||
['44815', '448', '15'], | ||
['28642726816697380', '286427268166973', '80'], | ||
['715268204', '7152682', '04'], | ||
['56848075487708204', '568480754877082', '04'], | ||
['6678451', '66784', '51'], | ||
['6648080174', '66480801', '74'], | ||
['366285202227487', '3662852022274', '87'], | ||
['608967', '6089', '67'], | ||
['7431953761', '74319537', '61'], | ||
['153131755331', '1531317553', '31'], | ||
['2291917', '22919', '17'], | ||
['43994543904', '439945439', '04'], | ||
['29640997713', '296409977', '13'], | ||
['000358899252034', '0003588992520', '34'], | ||
['0792052822', '07920528', '22'], | ||
['664423485859078', '6644234858590', '78'], | ||
['997482623', '9974826', '23'], | ||
['74259769628757', '742597696287', '57'], | ||
['000704224982126417', '0007042249821264', '17'], | ||
['629019490', '6290194', '90'], | ||
['951381918', '9513819', '18'], | ||
['58483690469', '584836904', '69'], | ||
['2779690110658105656137012565651624950', '27796901106581056561370125656516249', '50'], | ||
['7290046407591655641508592163006486357479642', '72900464075916556415085921630064863574796', '42'], | ||
['932206733032652055167366017586029', '9322067330326520551673660175860', '29'], | ||
['0292', '02', '92'], | ||
['30924835150563509', '309248351505635', '09'], | ||
['524649632973548834738386938017', '5246496329735488347383869380', '17'], | ||
['322448254908014251794825914427286053190', '3224482549080142517948259144272860531', '90'], | ||
['23500243820140280', '235002438201402', '80'], | ||
['5610062641345504953207405300713890206188126', '56100626413455049532074053007138902061881', '26'], | ||
['21525562', '215255', '62'], | ||
['1816620121284984592412938913019', '18166201212849845924129389130', '19'], | ||
['92420820312697691694564127286276729392660618089455', '924208203126976916945641272862767293926606180894', '55'], | ||
['054485853770631646395748486268', '0544858537706316463957484862', '68'], | ||
['25124011104805482203008027523', '251240111048054822030080275', '23'], | ||
['8654730620', '86547306', '20'], | ||
['260812975459327578860344265021526217185', '2608129754593275788603442650215262171', '85'], | ||
['36006992252038971008798559974233731771', '360069922520389710087985599742337317', '71'], | ||
['7287199458306312778764', '72871994583063127787', '64'], | ||
['76838648', '768386', '48'], | ||
['1815647', '18156', '47'], | ||
['261844772818947', '2618447728189', '47'], | ||
['1318659381411193605736042144949745322206318', '13186593814111936057360421449497453222063', '18'], | ||
['3816951', '38169', '51'], | ||
['532369369', '5323693', '69'], | ||
['443679', '4436', '79'], | ||
['780394802415324542674558990', '7803948024153245426745589', '90'], | ||
['7101095809493319410630796985060339784324206126880', '71010958094933194106307969850603397843242061268', '80'], | ||
['893152191348360150039194244597340', '8931521913483601500391942445973', '40'], | ||
['55085857871406033556199483715954', '550858578714060335561994837159', '54'], | ||
['18224823408703290397818358683', '182248234087032903978183586', '83'], | ||
['316792590737270063627957704', '3167925907372700636279577', '04'], | ||
['045501252249549249413190778849426192295', '0455012522495492494131907788494261922', '95'], | ||
['40586876169608405987', '405868761696084059', '87'], | ||
['7733759026645196682', '77337590266451966', '82'], | ||
['4930996', '49309', '96'], | ||
['3563799774218598390798308590832543839', '35637997742185983907983085908325438', '39'], | ||
['8052', '80', '52'], | ||
['919747358896', '9197473588', '96'], | ||
['476960059', '4769600', '59'], | ||
['9224232175957721954375860287966', '92242321759577219543758602879', '66'], | ||
['12006542700542680984284664008705360038097490857402', '120065427005426809842846640087053600380974908574', '02'], | ||
['6861248541583743473135766610115118552640', '68612485415837434731357666101151185526', '40'], | ||
['32202499992481656248059476354657492976181532449', '322024999924816562480594763546574929761815324', '49'], | ||
['1425187681352534', '14251876813525', '34'], | ||
['88341005', '883410', '05'], | ||
['83754383091999185891636242478134745153231810595196', '837543830919991858916362424781347451532318105951', '96'], | ||
['8234900186969819976585832', '82349001869698199765858', '32'], | ||
['05500482983960006910', '055004829839600069', '10'], | ||
['91617075914384200409098261870770716057567288711233', '916170759143842004090982618707707160575672887112', '33'], | ||
['6796299606148920705318592491555408617318', '67962996061489207053185924915554086173', '18'], | ||
['220873004452', '2208730044', '52'], | ||
['44772502268842667819803075386076608493474082', '447725022688426678198030753860766084934740', '82'], | ||
['3318821418190159927197892586292077116', '33188214181901599271978925862920771', '16'], | ||
['54926955795055931', '549269557950559', '31'], | ||
['53715523671212551268220445017640825', '537155236712125512682204450176408', '25'], | ||
['3486151850507560', '34861518505075', '60'], | ||
['4534390567499303478765964816486904115180420', '45343905674993034787659648164869041151804', '20'], | ||
['5045', '50', '45'], | ||
['50538', '505', '38'], | ||
['24757759386709053366538274576210657', '247577593867090533665382745762106', '57'], | ||
['664739816959376237603', '6647398169593762376', '03'], | ||
['57328954582818893432177570432421382', '573289545828188934321775704324213', '82'], | ||
['9928783114779426396', '99287831147794263', '96'], | ||
['532321684688182512582223244973154476477', '5323216846881825125822232449731544764', '77'], | ||
['5415158001410651645135', '54151580014106516451', '35'], | ||
['9522471955129742660719940107487554745647293931', '95224719551297426607199401074875547456472939', '31'], | ||
['7688152268150861398355895891785015272475484', '76881522681508613983558958917850152724754', '84'], | ||
['5251025984651678242935958235723602978881668817290', '52510259846516782429359582357236029788816688172', '90'], | ||
['668635896771227186', '6686358967712271', '86'], | ||
['33535814206438295673952597955072364615413638204463', '335358142064382956739525979550723646154136382044', '63'], | ||
['84803714597614333758042508756046777414160', '848037145976143337580425087560467774141', '60'], | ||
['9383712649135706346215676273739372853', '93837126491357063462156762737393728', '53'], | ||
['583', '5', '83'], | ||
['60223227', '602232', '27'], | ||
['6169641071917779935315194381377597396655', '61696410719177799353151943813775973966', '55'], | ||
['12413031420611321089628086618847981677460935', '124130314206113210896280866188479816774609', '35'], | ||
['3996387936315885601517965', '39963879363158856015179', '65'], | ||
['13364044911383596506838564198535710903315924', '133640449113835965068385641985357109033159', '24'], | ||
['741861982433243150', '7418619824332431', '50'], | ||
['15056697701630831441199290151357280017446', '150566977016308314411992901513572800174', '46'], | ||
['09996336', '099963', '36'], | ||
['636219587159691142223', '6362195871596911422', '23'], | ||
['6079660692771275027383551394922588248', '60796606927712750273835513949225882', '48'], | ||
['8040806371396463463342342839621731406764', '80408063713964634633423428396217314067', '64'], | ||
['00345073119702247280656743529519525501685', '003450731197022472806567435295195255016', '85'], | ||
['43341475824506382', '433414758245063', '82'], | ||
['5448457596983848111401941989219', '54484575969838481114019419892', '19'], | ||
['649437987622935856848596613915883214', '6494379876229358568485966139158832', '14'], | ||
['188944458', '1889444', '58'], | ||
['915872477192478501024743568', '9158724771924785010247435', '68'], | ||
['3656564733769602731893781070', '36565647337696027318937810', '70'], | ||
['3290262443814145312548940968938137419589455', '32902624438141453125489409689381374195894', '55'], | ||
['678613', '6786', '13'], | ||
['91009481457601404483', '910094814576014044', '83'], | ||
['412984353939015457569071224564254707046', '4129843539390154575690712245642547070', '46'], | ||
['614772837870259653166506', '6147728378702596531665', '06'], | ||
['234353', '2343', '53'], | ||
['785265635', '7852656', '35'], | ||
['9963425090164', '99634250901', '64'], | ||
['9428745311315234524365538662485496444423841', '94287453113152345243655386624854964444238', '41'], | ||
['439189512476121217915825110982942040225252757', '4391895124761212179158251109829420402252527', '57'], | ||
['8390473061683877906811984034148432171318851724', '83904730616838779068119840341484321713188517', '24'], | ||
['82359840141592910036647388591119831380', '823598401415929100366473885911198313', '80'], | ||
['67615417742250521160651728422365980863986416766511', '676154177422505211606517284223659808639864167665', '11'], | ||
['66688308656692246566783952163', '666883086566922465667839521', '63'], | ||
['837486057361', '8374860573', '61'], | ||
['31964181473517985429952827148895212338815475377', '319641814735179854299528271488952123388154753', '77'], | ||
['67319', '673', '19'], | ||
['81214689411669181583129707616492623062046973302', '812146894116691815831297076164926230620469733', '02'], | ||
['485893985556054582616151312972', '4858939855560545826161513129', '72'], | ||
['54141306213', '541413062', '13'], | ||
['6536922703460567171901698577626', '65369227034605671719016985776', '26'], | ||
['2939923919', '29399239', '19'], | ||
['8778932599499000826589972747378738179', '87789325994990008265899727473787381', '79'], | ||
['0988974486403569647517703', '09889744864035696475177', '03'], | ||
['32725603941733029059194832378985608318671', '327256039417330290591948323789856083186', '71'], | ||
['5023275195358139680', '50232751953581396', '80'], | ||
['25909635623820020027126835611054558', '259096356238200200271268356110545', '58'], | ||
['7010465484683976281626859101632157614512', '70104654846839762816268591016321576145', '12'], | ||
['4154680254610947966797670670872', '41546802546109479667976706708', '72'], | ||
['30767128640037830639233123051754816278285631064526', '307671286400378306392331230517548162782856310645', '26'], | ||
['163050890', '1630508', '90'], | ||
['19472686007025390720655906288082697429530696180625', '194726860070253907206559062880826974295306961806', '25'], | ||
['409199848495819029196016069447', '4091998484958190291960160694', '47'], | ||
['6258036789043', '62580367890', '43'], | ||
['5918', '59', '18'], | ||
['2062597776945548306', '20625977769455483', '06'], | ||
['060898513041788720153047687', '0608985130417887201530476', '87'], | ||
]; | ||
const invalid = [ | ||
['096123456769BE', '46'], | ||
['30006000011234567890189FR', '56'], | ||
['100000000123456789DE', '81'], | ||
['08100010000001234567890GR', '73'], | ||
['BCYP0000001234567890RO', '21'], | ||
['20000001234567891234SA', '70'], | ||
['21000813610123456789ES', '45'], | ||
['04835012345678009CH', '77'], | ||
['MIDL07009312345678GB', '12'], | ||
'79445', | ||
'9798', | ||
'375868282343', | ||
'24317820961419409380062077592753287576818X', | ||
'527', | ||
'792771904069435967228097245176385', | ||
'88627197127522', | ||
'6902269130131263083529X', | ||
'548948203397832', | ||
'92278188838120847901658822118304', | ||
'5099618826379340', | ||
'1747262671211458110201622103678877239', | ||
'02', | ||
'55098604002668708754215526576042', | ||
'74620658663', | ||
'159521179712250340292933005', | ||
'29953359122780133312161008', | ||
'627', | ||
'08061723756127709906398238671897839848265', | ||
'452955151417708029877138472392778844235727085', | ||
'21847137946520359971708', | ||
'0538751174173578757178081335', | ||
'34006787406365897930532982800542X', | ||
'1884234835259X', | ||
'1399725010830022064763538027708', | ||
'7440371066898040923897712997187846943801609X', | ||
'96167659675255861786506786706595115528775527987', | ||
'234581646043348631613899365', | ||
'558180185497', | ||
'929529690572330321262335864734556436990507', | ||
'2009130735472544574324044536', | ||
'74266664424137226850037', | ||
'437593769228280', | ||
'067872007400858375576543403345862964874211', | ||
'463147452888439812397', | ||
'7397790739904600059789214703291257637420', | ||
'48411119', | ||
'483915609925237034346273149994897', | ||
'639646988774501', | ||
'165458918162838196818109879799744928106X', | ||
'05875703073', | ||
'484916283986790636503840', | ||
'225696912606223', | ||
'0601029037106410827693160373235210', | ||
'3335592762690253635', | ||
'8858420874', | ||
'8945902336', | ||
'329825407478794475469116761', | ||
'9762491703995333287288', | ||
'69', | ||
'0648127364712623', | ||
'453812707844593193817287791988349097', | ||
'1777337239101', | ||
'3113918324692093', | ||
'159985403753777615165588217024865118857649558400', | ||
'576896540272691080861758646002333538131', | ||
'537177903370', | ||
'39332', | ||
'75973735848435872240', | ||
'3115490387581284772073100670', | ||
'3986', | ||
'24774442961145964623', | ||
'616124195859452', | ||
'484781621036814963095558490971', | ||
'034379197280800761341729908955', | ||
'51471X', | ||
'8795676050525689297875330227', | ||
'170877653463827455619284858668913635370419348327', | ||
'8051', | ||
'50435912142265428349380597', | ||
'403415446040276944792533576146128052646', | ||
'338426048', | ||
'458584036879', | ||
'3227013102158562907', | ||
'73268427849085052596', | ||
'735967547197', | ||
'0600467057120899413', | ||
'006446878553661232922915768727', | ||
'79102413170191613309796', | ||
'963780971924844', | ||
'805427822', | ||
'6133449450', | ||
'90680632351691951470X', | ||
'901639440415555918579', | ||
'57891973968260748980', | ||
'33774359122351317682402029672632880993985762', | ||
'00365734252354116390143745', | ||
'44444137', | ||
'687994963483332950306659841X', | ||
'6444101594390287210851791366', | ||
'235996705176809420430167289130774875324336864', | ||
'7683733973300309', | ||
'760558056790670294606707490146165174', | ||
'346', | ||
'7849933816', | ||
'4492417439373965789354941658202623536050295933', | ||
'040194405307872903163789318450313467488', | ||
'8876721030352', | ||
'8362946652717815642633', | ||
'71643784796795476677112972226', | ||
'6163102486091', | ||
'02', | ||
'3746549034989825452', | ||
'4750823745965148410506860782865180', | ||
'6788851113290276340298849', | ||
'39243501904967319180709618190X', | ||
'116706974560603', | ||
'380528676775136521975', | ||
'3723818', | ||
'718', | ||
'788772215218241394402150316395351269', | ||
'79985853846094', | ||
'4685308187910775511935', | ||
'719974614965292594478091717011', | ||
'3866293379018', | ||
'2478937987974868054514', | ||
'5315836936510337498521152393637788549191117884', | ||
'27669485260885400847947465', | ||
'14317170501741463696116320513655', | ||
'787150456525702488', | ||
'30322325568169542626', | ||
'49219593989', | ||
'201374265339936758561261638732421935041440674234', | ||
'16046177521252', | ||
'6642227777335546758083475793816767104X', | ||
'06544534', | ||
'0683794524145961', | ||
'4315218904775887126', | ||
]; | ||
// }}} | ||
const large = [ | ||
['096123456769BE', '71'], | ||
['30006000011234567890189FR', '76'], | ||
['100000000123456789DE', '91'], | ||
['08100010000001234567890GR', '96'], | ||
['BCYP0000001234567890RO', '09'], | ||
['20000001234567891234SA', '44'], | ||
['21000813610123456789ES', '79'], | ||
['04835012345678009CH', '56'], | ||
['MIDL07009312345678GB', '98'], | ||
]; | ||
common.testAlgo(algo, valid, invalid); | ||
}); | ||
describe(name + '.generate()', () => { | ||
it('generates a correct check digit', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.equal(algo.generate(num), checkdigit, `${name}.generate(${num})`); | ||
} | ||
}); | ||
it('is not affected by leading zeros', () => { | ||
for (let [num, checkdigit] of valid) { | ||
num = '0000' + num; | ||
assert.equal(algo.generate(num), checkdigit, `${name}.generate(${num})`); | ||
} | ||
}); | ||
it('accepts large decimal strings', () => { | ||
for (const [num, checkdigit] of large) { | ||
assert.equal(algo.generate(num), checkdigit, `${name}.generate(${num})`); | ||
} | ||
}); | ||
}); | ||
describe(name + '.validate()', () => { | ||
it('returns true if a code or a pair of number and check digit is valid', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.ok(algo.validate(num + checkdigit), `${name}.validate(${num + checkdigit})`); | ||
assert.ok(algo.validate(num, checkdigit), `${name}.validate(${num}, ${checkdigit})`); | ||
} | ||
}); | ||
it('returns false if a code or a pair of number and check digit is invalid', () => { | ||
for (const [num, checkdigit] of invalid) { | ||
assert.ok(!algo.validate(num + checkdigit), `!${name}.validate(${num + checkdigit})`); | ||
assert.ok(!algo.validate(num, checkdigit), `!${name}.validate(${num}, ${checkdigit})`); | ||
} | ||
}); | ||
it('is not affected by leading zeros', () => { | ||
for (let [num, checkdigit] of valid) { | ||
num = '0000' + num; | ||
assert.ok(algo.validate(num + checkdigit), `${name}.validate(${num + checkdigit})`); | ||
assert.ok(algo.validate(num, checkdigit), `${name}.validate(${num}, ${checkdigit})`); | ||
} | ||
}); | ||
it('accepts large decimal strings', () => { | ||
for (const [num, checkdigit] of large) { | ||
assert.ok(algo.validate(num + checkdigit), `${name}.validate(${num + checkdigit})`); | ||
assert.ok(algo.validate(num, checkdigit), `${name}.validate(${num}, ${checkdigit})`); | ||
} | ||
}); | ||
}); | ||
describe(name + '.encode()', () => { | ||
it('appends a correct check digit to a number', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.equal(algo.encode(num), num + checkdigit, `${name}.encode(${num})`); | ||
} | ||
}); | ||
it('is not affected by leading zeros', () => { | ||
for (let [num, checkdigit] of valid) { | ||
num = '0000' + num; | ||
assert.equal(algo.encode(num), num + checkdigit, `${name}.encode(${num})`); | ||
} | ||
}); | ||
it('accepts large decimal strings', () => { | ||
for (const [num, checkdigit] of large) { | ||
assert.equal(algo.encode(num), num + checkdigit, `${name}.encode(${num})`); | ||
} | ||
}); | ||
}); | ||
describe(name + '.decode()', () => { | ||
it('separates the leading digits and the last digit', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.deepEqual(algo.decode(num + checkdigit), [num, checkdigit], `${name}.decode(${num + checkdigit})`); | ||
} | ||
}); | ||
it('accepts large decimal strings', () => { | ||
for (const [num, checkdigit] of large) { | ||
assert.deepEqual(algo.decode(num + checkdigit), [num, checkdigit], `${name}.decode(${num + checkdigit})`); | ||
} | ||
}); | ||
}); | ||
describe('bulk example test', () => { | ||
const examples = [ | ||
'096123456769BE71', | ||
'30006000011234567890189FR76', | ||
'100000000123456789DE91', | ||
'08100010000001234567890GR96', | ||
'BCYP0000001234567890RO09', | ||
'20000001234567891234SA44', | ||
'21000813610123456789ES79', | ||
'04835012345678009CH56', | ||
'MIDL07009312345678GB98', | ||
]; | ||
it('applies the four functions to collected valid examples', () => { | ||
for (const e of examples) { | ||
const [num, checkdigit] = algo.decode(e); | ||
assert.equal(algo.generate(num), checkdigit, `${name}.generate(${num})`); | ||
assert.ok(algo.validate(e), `${name}.validate(${e})`); | ||
assert.ok(algo.validate(num, checkdigit), `${name}.validate(${num}, ${checkdigit})`); | ||
assert.equal(algo.encode(num), e, `${name}.encode(${num})`); | ||
} | ||
}); | ||
}); | ||
}); | ||
// vim: fdm=marker fmr& |
@@ -0,156 +1,479 @@ | ||
'use strict'; | ||
const assert = require('assert').strict; | ||
const cdigit = require('..'); | ||
const common = require('./common'); | ||
const algo = require('..').verhoeff; | ||
describe('Verhoeff algorithm', () => { | ||
const name = 'verhoeff'; | ||
const algo = cdigit[name]; | ||
// {{{ List sample strings | ||
const valid = [ | ||
['236', '3'], ['7728635820', '7'], ['04931803', '7'], ['007517311', '0'], | ||
['01024845', '5'], ['06568986', '2'], ['06479718', '7'], ['0202052', '3'], | ||
['527035', '3'], ['01750233', '6'], ['009557265', '6'], ['08682273', '0'], | ||
['2425089', '5'], ['8820375', '8'], ['6228694', '7'], ['005322797', '5'], | ||
['7459117', '0'], ['009104556', '8'], ['04717249', '7'], ['002717051', '3'], | ||
['09075696', '1'], ['04370338', '7'], ['01168676', '1'], ['2919413', '6'], | ||
['01224799', '6'], ['005339970', '2'], ['04825408', '1'], ['6711810', '9'], | ||
['9011851', '9'], ['004906597', '6'], ['04606554', '3'], ['0151723', '7'], | ||
['03818633', '7'], ['009944956', '8'], | ||
['2363', '236', '3'], | ||
['77286358207', '7728635820', '7'], | ||
['049318037', '04931803', '7'], | ||
['0075173110', '007517311', '0'], | ||
['010248455', '01024845', '5'], | ||
['065689862', '06568986', '2'], | ||
['064797187', '06479718', '7'], | ||
['02020523', '0202052', '3'], | ||
['5270353', '527035', '3'], | ||
['017502336', '01750233', '6'], | ||
['0095572656', '009557265', '6'], | ||
['086822730', '08682273', '0'], | ||
['24250895', '2425089', '5'], | ||
['88203758', '8820375', '8'], | ||
['62286947', '6228694', '7'], | ||
['0053227975', '005322797', '5'], | ||
['74591170', '7459117', '0'], | ||
['0091045568', '009104556', '8'], | ||
['047172497', '04717249', '7'], | ||
['0027170513', '002717051', '3'], | ||
['090756961', '09075696', '1'], | ||
['043703387', '04370338', '7'], | ||
['011686761', '01168676', '1'], | ||
['29194136', '2919413', '6'], | ||
['012247996', '01224799', '6'], | ||
['0053399702', '005339970', '2'], | ||
['048254081', '04825408', '1'], | ||
['67118109', '6711810', '9'], | ||
['90118519', '9011851', '9'], | ||
['0049065976', '004906597', '6'], | ||
['046065543', '04606554', '3'], | ||
['01517237', '0151723', '7'], | ||
['038186337', '03818633', '7'], | ||
['0099449568', '009944956', '8'], | ||
['0619608022586647594299264394240912409', '061960802258664759429926439424091240', '9'], | ||
['751571178333174470538369159358920359', '75157117833317447053836915935892035', '9'], | ||
['0059362834268511520978245333915466478', '005936283426851152097824533391546647', '8'], | ||
['0411748883402279030408145005815637207', '041174888340227903040814500581563720', '7'], | ||
['00414968085303554412899791050931080521', '0041496808530355441289979105093108052', '1'], | ||
['00984648354763114612218738978653552807', '0098464835476311461221873897865355280', '7'], | ||
['0149658159204466596324134442965160860', '014965815920446659632413444296516086', '0'], | ||
['00124252239509639940057503707379526955', '0012425223950963994005750370737952695', '5'], | ||
['570365439806894784840608094925142962', '57036543980689478484060809492514296', '2'], | ||
['530094313035154310010313087969542705', '53009431303515431001031308796954270', '5'], | ||
['00511271038537428606221225025286500904', '0051127103853742860622122502528650090', '4'], | ||
['0092181662135345456478828864059910447', '009218166213534545647882886405991044', '7'], | ||
['0239702459361598582949414192067779844', '023970245936159858294941419206777984', '4'], | ||
['004850022011833856780912143887483972', '00485002201183385678091214388748397', '2'], | ||
['632037560678057215526114539815843668', '63203756067805721552611453981584366', '8'], | ||
['0723623766645502131239247939742471', '072362376664550213123924793974247', '1'], | ||
['2363', '236', '3'], | ||
['5357084', '535708', '4'], | ||
['69954516', '6995451', '6'], | ||
['81335211', '8133521', '1'], | ||
['44593650', '4459365', '0'], | ||
['0049950638', '004995063', '8'], | ||
['03896025', '0389602', '5'], | ||
['0068716540', '006871654', '0'], | ||
['0025701100', '002570110', '0'], | ||
['58181453', '5818145', '3'], | ||
['66476930', '6647693', '0'], | ||
['60158862', '6015886', '2'], | ||
['031950144', '03195014', '4'], | ||
['076884255', '07688425', '5'], | ||
['027119369', '02711936', '9'], | ||
['46200920', '4620092', '0'], | ||
['99390631', '9939063', '1'], | ||
['23309489', '2330948', '9'], | ||
['0052478848', '005247884', '8'], | ||
['0075272466', '007527246', '6'], | ||
['0022429632', '002242963', '2'], | ||
['82671168', '8267116', '8'], | ||
['25257216', '2525721', '6'], | ||
['6204713', '620471', '3'], | ||
['0096880514', '009688051', '4'], | ||
['0085591604', '008559160', '4'], | ||
['0099719045', '009971904', '5'], | ||
['84033346', '8403334', '6'], | ||
['55019999', '5501999', '9'], | ||
['24068703', '2406870', '3'], | ||
['16072082', '1607208', '2'], | ||
['059633257', '05963325', '7'], | ||
['77908591', '7790859', '1'], | ||
['090156671', '09015667', '1'], | ||
['97063984', '9706398', '4'], | ||
['039630056', '03963005', '6'], | ||
['73132699', '7313269', '9'], | ||
['012818089', '01281808', '9'], | ||
['0037550877', '003755087', '7'], | ||
['039180764', '03918076', '4'], | ||
['050640092', '05064009', '2'], | ||
['0013503619', '001350361', '9'], | ||
['008152311', '00815231', '1'], | ||
['0076970850', '007697085', '0'], | ||
['059735434', '05973543', '4'], | ||
['59927949', '5992794', '9'], | ||
['0062617894', '006261789', '4'], | ||
['3994053', '399405', '3'], | ||
['0041515823', '004151582', '3'], | ||
['028035955', '02803595', '5'], | ||
['0026902759', '002690275', '9'], | ||
['043346511', '04334651', '1'], | ||
['058307931', '05830793', '1'], | ||
['005379201', '00537920', '1'], | ||
['088748521', '08874852', '1'], | ||
['045303743', '04530374', '3'], | ||
['037986200', '03798620', '0'], | ||
['94141754', '9414175', '4'], | ||
['0044746127', '004474612', '7'], | ||
['0037893182', '003789318', '2'], | ||
['048112347', '04811234', '7'], | ||
['001007449', '00100744', '9'], | ||
['28957659', '2895765', '9'], | ||
['70534852', '7053485', '2'], | ||
['0043697584', '004369758', '4'], | ||
['28345593', '2834559', '3'], | ||
['0068947798', '006894779', '8'], | ||
['0068186947', '006818694', '7'], | ||
['047409719', '04740971', '9'], | ||
['058079449', '05807944', '9'], | ||
['08798054', '0879805', '4'], | ||
['0027584523', '002758452', '3'], | ||
['008760498', '00876049', '8'], | ||
['005723856', '00572385', '6'], | ||
['022728444', '02272844', '4'], | ||
['6198089', '619808', '9'], | ||
['097573240', '09757324', '0'], | ||
['80088936', '8008893', '6'], | ||
['046478565', '04647856', '5'], | ||
['48387817', '4838781', '7'], | ||
['0096366066', '009636606', '6'], | ||
['045766558', '04576655', '8'], | ||
['087921639', '08792163', '9'], | ||
['33029563', '3302956', '3'], | ||
['007928987', '00792898', '7'], | ||
['25136481', '2513648', '1'], | ||
['0079785128', '007978512', '8'], | ||
['67271824', '6727182', '4'], | ||
['096873288', '09687328', '8'], | ||
['0051034541', '005103454', '1'], | ||
['76638436', '7663843', '6'], | ||
['74406025', '7440602', '5'], | ||
['56077139', '5607713', '9'], | ||
['94780690', '9478069', '0'], | ||
['0029350101', '002935010', '1'], | ||
['010109963', '01010996', '3'], | ||
['30388490', '3038849', '0'], | ||
['079739588', '07973958', '8'], | ||
['009479211', '00947921', '1'], | ||
['0082839775', '008283977', '5'], | ||
['096913209', '09691320', '9'], | ||
['88776574', '8877657', '4'], | ||
['0057514795', '005751479', '5'], | ||
['30721109', '3072110', '9'], | ||
['83170592', '8317059', '2'], | ||
['43313999', '4331399', '9'], | ||
['007048883', '00704888', '3'], | ||
['051140200', '05114020', '0'], | ||
['73940783', '7394078', '3'], | ||
['0091891832', '009189183', '2'], | ||
['49272239', '4927223', '9'], | ||
['0068185128', '006818512', '8'], | ||
['67617282', '6761728', '2'], | ||
['65713108', '6571310', '8'], | ||
['099946176', '09994617', '6'], | ||
['0070716474', '007071647', '4'], | ||
['02300297', '0230029', '7'], | ||
['034150296', '03415029', '6'], | ||
['010254002', '01025400', '2'], | ||
['86779951', '8677995', '1'], | ||
['086961859', '08696185', '9'], | ||
['28995408', '2899540', '8'], | ||
['38121883', '3812188', '3'], | ||
['045117546', '04511754', '6'], | ||
['02319886', '0231988', '6'], | ||
['65649070', '6564907', '0'], | ||
['0057979702', '005797970', '2'], | ||
['0092484360', '009248436', '0'], | ||
['74295647', '7429564', '7'], | ||
['47472527385003521126608921299727', '4747252738500352112660892129972', '7'], | ||
['578651888655276976272240700845', '57865188865527697627224070084', '5'], | ||
['471473464859818700038365081171897410871366885', '47147346485981870003836508117189741087136688', '5'], | ||
['8067575', '806757', '5'], | ||
['81630414138626', '8163041413862', '6'], | ||
['808170781119145175099445060453425555444', '80817078111914517509944506045342555544', '4'], | ||
['58484', '5848', '4'], | ||
['6958108080046405118603227972409226935222438', '695810808004640511860322797240922693522243', '8'], | ||
['07276417', '0727641', '7'], | ||
['07474016544847316388583741378626812', '0747401654484731638858374137862681', '2'], | ||
['4501484854892115164027230015029964933752', '450148485489211516402723001502996493375', '2'], | ||
['63949435180977', '6394943518097', '7'], | ||
['788458292213', '78845829221', '3'], | ||
['215723382047296102691497779668798420918', '21572338204729610269149777966879842091', '8'], | ||
['7841976343306', '784197634330', '6'], | ||
['309616646381463309589638776224567255605', '30961664638146330958963877622456725560', '5'], | ||
['417448540225969640760547898468296', '41744854022596964076054789846829', '6'], | ||
['1562824', '156282', '4'], | ||
['15970012725138617819391854596792989987200467755', '1597001272513861781939185459679298998720046775', '5'], | ||
['87143195401943', '8714319540194', '3'], | ||
['3511818922292078482112508860355400343974705', '351181892229207848211250886035540034397470', '5'], | ||
['13247842413305984780552', '1324784241330598478055', '2'], | ||
['7414118746130251062242934128847394064854', '741411874613025106224293412884739406485', '4'], | ||
['058050107625', '05805010762', '5'], | ||
['0718848221770851190449', '071884822177085119044', '9'], | ||
['96446882342797788647357', '9644688234279778864735', '7'], | ||
['51592434201317972', '5159243420131797', '2'], | ||
['42028413572001147', '4202841357200114', '7'], | ||
['2281584', '228158', '4'], | ||
['151223', '15122', '3'], | ||
['471396150613484246898401412276255028410253', '47139615061348424689840141227625502841025', '3'], | ||
['87325336031732956975400', '8732533603173295697540', '0'], | ||
['536603402', '53660340', '2'], | ||
['1935188887320320588509107013', '193518888732032058850910701', '3'], | ||
['15', '1', '5'], | ||
['95581615533245229832000892562896565', '9558161553324522983200089256289656', '5'], | ||
['9541278279520013845028105960399371', '954127827952001384502810596039937', '1'], | ||
['510245767802563133781845589882291364003', '51024576780256313378184558988229136400', '3'], | ||
['10434044', '1043404', '4'], | ||
['073860761669551677038835392199279127099187962827', '07386076166955167703883539219927912709918796282', '7'], | ||
['7191124612264058739662120965466717966550', '719112461226405873966212096546671796655', '0'], | ||
['6704317210', '670431721', '0'], | ||
['28353789785306988169937598516777367665931534', '2835378978530698816993759851677736766593153', '4'], | ||
['32160861338393661758422278283202307495841', '3216086133839366175842227828320230749584', '1'], | ||
['245610040963', '24561004096', '3'], | ||
['2982464111', '298246411', '1'], | ||
['3400462952974306349992685290192348', '340046295297430634999268529019234', '8'], | ||
['847477637', '84747763', '7'], | ||
['5961914703649251855229193000514562288442827', '596191470364925185522919300051456228844282', '7'], | ||
['7512530788287053483979398673', '751253078828705348397939867', '3'], | ||
['50485096365465538783533512676763572121', '5048509636546553878353351267676357212', '1'], | ||
['208103268385740219343957958', '20810326838574021934395795', '8'], | ||
['8368895397', '836889539', '7'], | ||
['7934342452076413107847989347700180234', '793434245207641310784798934770018023', '4'], | ||
['074161875867002771716229961205855106863', '07416187586700277171622996120585510686', '3'], | ||
['446103877392', '44610387739', '2'], | ||
['4355', '435', '5'], | ||
['448492377955969095272190781552113435139417574373', '44849237795596909527219078155211343513941757437', '3'], | ||
['12899947947170761264', '1289994794717076126', '4'], | ||
['040523019081487822922837019340897139', '04052301908148782292283701934089713', '9'], | ||
['71152215707236542103615318972', '7115221570723654210361531897', '2'], | ||
['572522654876736485951787730406547757558170025', '57252265487673648595178773040654775755817002', '5'], | ||
['72863113476483611929330330245621530717163', '7286311347648361192933033024562153071716', '3'], | ||
['89', '8', '9'], | ||
['739343909307920902501', '73934390930792090250', '1'], | ||
['1979472757954783750385710848268504812833714803', '197947275795478375038571084826850481283371480', '3'], | ||
['801330544915027109196158068475984369', '80133054491502710919615806847598436', '9'], | ||
['306816716504605142886528627590934314', '30681671650460514288652862759093431', '4'], | ||
['6419638721565866077315422954178010289', '641963872156586607731542295417801028', '9'], | ||
['248446239124543958', '24844623912454395', '8'], | ||
['0653613774', '065361377', '4'], | ||
['5930470396799118957238898772652479', '593047039679911895723889877265247', '9'], | ||
['055372', '05537', '2'], | ||
['70', '7', '0'], | ||
['4145765249', '414576524', '9'], | ||
['20325178315256589550373445619221377123', '2032517831525658955037344561922137712', '3'], | ||
['9954988155696836224117777421556669060608662', '995498815569683622411777742155666906060866', '2'], | ||
['1387846460419688511283004110357890669879047611', '138784646041968851128300411035789066987904761', '1'], | ||
['572019655926922379634494349391127', '57201965592692237963449434939112', '7'], | ||
['4872807203148348149411848114091398613988419', '487280720314834814941184811409139861398841', '9'], | ||
['6526277165122432610041054365731351240690051502737', '652627716512243261004105436573135124069005150273', '7'], | ||
['07381191527051124609426545', '0738119152705112460942654', '5'], | ||
['023163066751725159691224423016152158517', '02316306675172515969122442301615215851', '7'], | ||
['0697674179414175376627439735574', '069767417941417537662743973557', '4'], | ||
['074490578393501341755098326537511336', '07449057839350134175509832653751133', '6'], | ||
['153545090518847318456269', '15354509051884731845626', '9'], | ||
['402863024653572433736245', '40286302465357243373624', '5'], | ||
['1284322', '128432', '2'], | ||
['88278997436190282688248217481211460', '8827899743619028268824821748121146', '0'], | ||
['052703144595436275923', '05270314459543627592', '3'], | ||
['76439061807040985349996486', '7643906180704098534999648', '6'], | ||
['85371107', '8537110', '7'], | ||
['423654471577860242914904617521154', '42365447157786024291490461752115', '4'], | ||
['5649', '564', '9'], | ||
['8861', '886', '1'], | ||
['655483045031408187935981916413961780031', '65548304503140818793598191641396178003', '1'], | ||
['6971854', '697185', '4'], | ||
['730951904054139647338147012919777455444749', '73095190405413964733814701291977745544474', '9'], | ||
['50464364886091310495544560', '5046436488609131049554456', '0'], | ||
['3387503764677101855289964736741318597236518249', '338750376467710185528996473674131859723651824', '9'], | ||
['2653011348', '265301134', '8'], | ||
['127665928440836556142027023571267152476', '12766592844083655614202702357126715247', '6'], | ||
['31240141993433584122839559', '3124014199343358412283955', '9'], | ||
['68837231136431479562974626257', '6883723113643147956297462625', '7'], | ||
['9251702753595140965816982746786900887592', '925170275359514096581698274678690088759', '2'], | ||
['4879768783355165370221', '487976878335516537022', '1'], | ||
['70284403193', '7028440319', '3'], | ||
['09848955112096469768425398373967974265', '0984895511209646976842539837396797426', '5'], | ||
['670477835', '67047783', '5'], | ||
['2459360227254053907', '245936022725405390', '7'], | ||
['180380021004799556285995669135', '18038002100479955628599566913', '5'], | ||
['1546125953852364176498', '154612595385236417649', '8'], | ||
['929348568675219466259529221975249397514', '92934856867521946625952922197524939751', '4'], | ||
['501825246366907057995377364062640189924021287', '50182524636690705799537736406264018992402128', '7'], | ||
['865181199397373167098794254727', '86518119939737316709879425472', '7'], | ||
['134364940266957202370127417', '13436494026695720237012741', '7'], | ||
['96708106542312635035940844', '9670810654231263503594084', '4'], | ||
['231365031186841942', '23136503118684194', '2'], | ||
['76014375185465912722984856802', '7601437518546591272298485680', '2'], | ||
['177233935255610360211', '17723393525561036021', '1'], | ||
['7668121637314', '766812163731', '4'], | ||
['166530058025276973855806544144691350586999', '16653005802527697385580654414469135058699', '9'], | ||
['010', '01', '0'], | ||
['67770724309815823897683380144132516', '6777072430981582389768338014413251', '6'], | ||
['0052413', '005241', '3'], | ||
['5958342704033684', '595834270403368', '4'], | ||
['72565354325345794182571053458856866805007', '7256535432534579418257105345885686680500', '7'], | ||
['432091311801835', '43209131180183', '5'], | ||
]; | ||
const invalid = [ | ||
['236', '0'], ['236', '1'], ['236', '2'], ['236', '4'], ['236', '5'], | ||
['236', '6'], ['236', '7'], ['236', '8'], ['236', '9'], | ||
['00228883', '2'], ['6866000', '0'], ['8565988', '5'], ['0293732', '6'], | ||
['3576801', '0'], ['04136644', '9'], ['0420654', '4'], ['002014421', '9'], | ||
['1645150', '5'], ['003249561', '2'], ['5632161', '5'], ['04934896', '4'], | ||
['02924190', '2'], ['2416374', '0'], ['0901786', '1'], ['004601776', '5'], | ||
['04049758', '3'], ['3379093', '9'], ['01489667', '7'], ['3281840', '3'], | ||
['04832177', '9'], ['0318463', '6'], ['03754040', '8'], ['7760252', '0'], | ||
['06635773', '7'], ['02511903', '6'], ['03192825', '0'], ['001234146', '5'], | ||
['130834', '4'], ['009070302', '9'], ['06588890', '7'], ['006164297', '0'], | ||
'2360', | ||
'2361', | ||
'2362', | ||
'2364', | ||
'2365', | ||
'2366', | ||
'2367', | ||
'2368', | ||
'2369', | ||
'002288832', | ||
'68660000', | ||
'85659885', | ||
'02937326', | ||
'35768010', | ||
'041366449', | ||
'04206544', | ||
'0020144219', | ||
'16451505', | ||
'0032495612', | ||
'56321615', | ||
'049348964', | ||
'029241902', | ||
'24163740', | ||
'09017861', | ||
'0046017765', | ||
'040497583', | ||
'33790939', | ||
'014896677', | ||
'32818403', | ||
'048321779', | ||
'03184636', | ||
'037540408', | ||
'77602520', | ||
'066357737', | ||
'025119036', | ||
'031928250', | ||
'0012341465', | ||
'1308344', | ||
'0090703029', | ||
'065888907', | ||
'0061642970', | ||
'280579137429739104195', | ||
'6085681426257633536000798077875', | ||
'717697090252304489738263410', | ||
'6882072646996151507423372', | ||
'60601', | ||
'13406', | ||
'61848424302551420827686325266353', | ||
'18829360909683931375487214661261559711480', | ||
'53193090772', | ||
'2332983077375559555860', | ||
'986', | ||
'130574480553649829079539073810665241225670', | ||
'310771541553596567492583172313', | ||
'3118992092394502110871104425402017050423252', | ||
'33987166780818899', | ||
'664906519703194714723029601693638986768533', | ||
'9204430832762997906229471953', | ||
'6391549362', | ||
'206976922680937684543527077691116', | ||
'20428', | ||
'738298975733603081758558164726183', | ||
'1607521933', | ||
'02912319235376434218185', | ||
'046563570274025', | ||
'1750542573503540', | ||
'9673732456719755291477112860274078452184', | ||
'7780777342679090497838589448116828434784', | ||
'653783514618805876413691316433', | ||
'324373637', | ||
'989695026144622025052971577726505622010850', | ||
'991424657728753644764865549859267977398898514', | ||
'648165508153387616881148814723686742865545', | ||
'392782253130738353940751', | ||
'814897949618082620108870', | ||
'6386993373893746257540', | ||
'41691800168046', | ||
'457030608141', | ||
'6841263793087756799906446', | ||
'9552951545919796571', | ||
'6971814446267281823', | ||
'71138152734193368836', | ||
'5545665534059345435252627434636333', | ||
'6813918766249588053530643625441398030467329759007', | ||
'33282033703724369522097592284', | ||
'009234', | ||
'17040798285281778', | ||
'87763635143467532856614261038600256', | ||
'41850408446012103168093140', | ||
'578', | ||
'092709999043408408684492051307235055614873', | ||
'88543035268355329879297424354145550400', | ||
'1774', | ||
'4531788126951511103018571062388558', | ||
'990134523870477090466181880843987291949885959241', | ||
'988484545707146475187582193', | ||
'13337814823379738884559814719', | ||
'837211845206674130064313', | ||
'365953110743193509999242919430961280', | ||
'0007044908113930', | ||
'075022040642805376993902144404403428563883422237', | ||
'33041762152470308493652005', | ||
'78480454218181044968858455391848174964677306', | ||
'024109559581284684764809003959256', | ||
'27542905916293537645393816923191631', | ||
'28559386938553', | ||
'2158119067583293205433009345094', | ||
'653429177787877618131', | ||
'239440969341144732177982591227', | ||
'3618483', | ||
'8945327597727070192113523493978684571944', | ||
'69191599639328935966', | ||
'868030643121162962', | ||
'61257684159688232312000684', | ||
'5751527223278021256437459438707106639209766850', | ||
'868492230934203271850368', | ||
'64456538820024959414090523', | ||
'14057229952448069389181103384', | ||
'183606217130457254050397961947309230587257976661', | ||
'7712839', | ||
'048375675356326690428997', | ||
'897', | ||
'03785499703353634697972', | ||
'10734850666647953264643789306752083992665', | ||
'83664186446638946172063939043141245747018', | ||
'08570172023118587324474475288184', | ||
'9827812806', | ||
'632514063483704528', | ||
'9638748568043987540240353189274026699231', | ||
'482875376245121369425869256810185513759457', | ||
'496299499399999976434325660531', | ||
'6446996589728505784811227428941', | ||
'63335425987989068377', | ||
'157448491539381037244214418880956255715', | ||
'35841884324640379382132453', | ||
'019678418971707105068759902113377348121832', | ||
'8943112033276', | ||
'7577068377534033599768602362104434986992', | ||
'507619306788637390321936940123708454505871099', | ||
'71372591550821', | ||
'73501885396580', | ||
'532386457638656638468285496100913781', | ||
'483035579251939931672119874624522808', | ||
'9008', | ||
'6441745654676591', | ||
'986', | ||
'09853471132', | ||
'0199133208081338774360969274932', | ||
'30539635149205750334410285067601694843525155', | ||
'6360210158582695', | ||
'27580599', | ||
'743987443332', | ||
'799008863095', | ||
'96450655620119702297287893', | ||
]; | ||
// }}} | ||
const large = [ | ||
['061960802258664759429926439424091240', '9'], | ||
['75157117833317447053836915935892035', '9'], | ||
['005936283426851152097824533391546647', '8'], | ||
['041174888340227903040814500581563720', '7'], | ||
['0041496808530355441289979105093108052', '1'], | ||
['0098464835476311461221873897865355280', '7'], | ||
['014965815920446659632413444296516086', '0'], | ||
['0012425223950963994005750370737952695', '5'], | ||
['57036543980689478484060809492514296', '2'], | ||
['53009431303515431001031308796954270', '5'], | ||
['0051127103853742860622122502528650090', '4'], | ||
['009218166213534545647882886405991044', '7'], | ||
['023970245936159858294941419206777984', '4'], | ||
['00485002201183385678091214388748397', '2'], | ||
['63203756067805721552611453981584366', '8'], | ||
['072362376664550213123924793974247', '1'], | ||
]; | ||
common.testAlgo(algo, valid, invalid); | ||
}); | ||
describe(name + '.generate()', () => { | ||
it('generates a correct check digit', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.equal(algo.generate(num), checkdigit, `${name}.generate(${num})`); | ||
} | ||
}); | ||
it('accepts large decimal strings', () => { | ||
for (const [num, checkdigit] of large) { | ||
assert.equal(algo.generate(num), checkdigit, `${name}.generate(${num})`); | ||
} | ||
}); | ||
}); | ||
describe(name + '.validate()', () => { | ||
it('returns true if a code or a pair of number and check digit is valid', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.ok(algo.validate(num + checkdigit), `${name}.validate(${num + checkdigit})`); | ||
assert.ok(algo.validate(num, checkdigit), `${name}.validate(${num}, ${checkdigit})`); | ||
} | ||
}); | ||
it('returns false if a code or a pair of number and check digit is invalid', () => { | ||
for (const [num, checkdigit] of invalid) { | ||
assert.ok(!algo.validate(num + checkdigit), `!${name}.validate(${num + checkdigit})`); | ||
assert.ok(!algo.validate(num, checkdigit), `!${name}.validate(${num}, ${checkdigit})`); | ||
} | ||
}); | ||
it('accepts large decimal strings', () => { | ||
for (const [num, checkdigit] of large) { | ||
assert.ok(algo.validate(num + checkdigit), `${name}.validate(${num + checkdigit})`); | ||
assert.ok(algo.validate(num, checkdigit), `${name}.validate(${num}, ${checkdigit})`); | ||
} | ||
}); | ||
}); | ||
describe(name + '.encode()', () => { | ||
it('appends a correct check digit to a number', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.equal(algo.encode(num), num + checkdigit, `${name}.encode(${num})`); | ||
} | ||
}); | ||
it('accepts large decimal strings', () => { | ||
for (const [num, checkdigit] of large) { | ||
assert.equal(algo.encode(num), num + checkdigit, `${name}.encode(${num})`); | ||
} | ||
}); | ||
}); | ||
describe(name + '.decode()', () => { | ||
it('separates the leading digits and the last digit', () => { | ||
for (const [num, checkdigit] of valid) { | ||
assert.deepEqual(algo.decode(num + checkdigit), [num, checkdigit], `${name}.decode(${num + checkdigit})`); | ||
} | ||
}); | ||
it('accepts large decimal strings', () => { | ||
for (const [num, checkdigit] of large) { | ||
assert.deepEqual(algo.decode(num + checkdigit), [num, checkdigit], `${name}.decode(${num + checkdigit})`); | ||
} | ||
}); | ||
}); | ||
describe('bulk example test', () => { | ||
const examples = [ | ||
'2363', '5357084', '69954516', '81335211', '44593650', '0049950638', | ||
'03896025', '0068716540', '0025701100', '58181453', '66476930', | ||
'60158862', '031950144', '076884255', '027119369', '46200920', '99390631', | ||
'23309489', '0052478848', '0075272466', '0022429632', '82671168', | ||
'25257216', '6204713', '0096880514', '0085591604', '0099719045', | ||
'84033346', '55019999', '24068703', '16072082', '059633257', '77908591', | ||
'090156671', '97063984', '039630056', '73132699', '012818089', | ||
'0037550877', '039180764', '050640092', '0013503619', '008152311', | ||
'0076970850', '059735434', '59927949', '0062617894', '3994053', | ||
'0041515823', '028035955', '0026902759', '043346511', '058307931', | ||
'005379201', '088748521', '045303743', '037986200', '94141754', | ||
'0044746127', '0037893182', '048112347', '001007449', '28957659', | ||
'70534852', '0043697584', '28345593', '0068947798', '0068186947', | ||
'047409719', '058079449', '08798054', '0027584523', '008760498', | ||
'005723856', '022728444', '6198089', '097573240', '80088936', '046478565', | ||
'48387817', '0096366066', '045766558', '087921639', '33029563', | ||
'007928987', '25136481', '0079785128', '67271824', '096873288', | ||
'0051034541', '76638436', '74406025', '56077139', '94780690', | ||
'0029350101', '010109963', '30388490', '079739588', '009479211', | ||
'0082839775', '096913209', '88776574', '0057514795', '30721109', | ||
'83170592', '43313999', '007048883', '051140200', '73940783', | ||
'0091891832', '49272239', '0068185128', '67617282', '65713108', | ||
'099946176', '0070716474', '02300297', '034150296', '010254002', | ||
'86779951', '086961859', '28995408', '38121883', '045117546', '02319886', | ||
'65649070', '0057979702', '0092484360', '74295647', | ||
]; | ||
it('applies the four functions to collected valid examples', () => { | ||
for (const e of examples) { | ||
const [num, checkdigit] = [e.slice(0, -1), e.slice(-1)]; | ||
assert.equal(algo.generate(num), checkdigit, `${name}.generate(${num})`); | ||
assert.ok(algo.validate(e), `${name}.validate(${e})`); | ||
assert.ok(algo.validate(num, checkdigit), `${name}.validate(${num}, ${checkdigit})`); | ||
assert.equal(algo.encode(num), e, `${name}.encode(${num})`); | ||
assert.deepEqual(algo.decode(e), [num, checkdigit], `${name}.decode(${e})`); | ||
} | ||
}); | ||
}); | ||
}); | ||
// vim: fdm=marker fmr& |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
200932
53
4230
99
5
1