From e56de7b26441984897202ce9722252a3a021283f Mon Sep 17 00:00:00 2001 From: Eric Cheng Date: Sat, 21 May 2022 10:52:44 -0400 Subject: [PATCH 1/9] feat: working luhnCheck func --- test/support/luhnCheck.ts | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/test/support/luhnCheck.ts b/test/support/luhnCheck.ts index fb4e0bb0fa9..b8fff49fadc 100644 --- a/test/support/luhnCheck.ts +++ b/test/support/luhnCheck.ts @@ -1,18 +1,19 @@ -export function luhnCheck(number: string): boolean { - number = number.replace(/\D/g, ''); - let split: string[] | number[] = number.split(''); - split = split.map((num) => parseInt(num)); - const check = split.pop(); - split.reverse(); - split = split.map((num, index) => { - if (index % 2 === 0) { - num *= 2; - if (num > 9) { - num -= 9; +export function luhnCheck(ccNumber: string): boolean { + if (ccNumber.includes('-')) { + ccNumber = ccNumber.replace(/-/g, ''); + } + let sum = 0; + let alternate = false; + for (let i = ccNumber.length - 1; i >= 0; i--) { + let n = parseInt(ccNumber.substring(i, i + 1)); + if (alternate) { + n *= 2; + if (n > 9) { + n = (n % 10) + 1; } } - return num; - }); - const sum = split.reduce((prev, curr) => prev + curr); - return sum % 10 === check; + sum += n; + alternate = !alternate; + } + return sum % 10 === 0; } From a61a44025ac851a35a01015887262efd32f295a1 Mon Sep 17 00:00:00 2001 From: Eric Cheng Date: Sat, 21 May 2022 12:06:36 -0400 Subject: [PATCH 2/9] chore: remove extraneous if statement --- test/support/luhnCheck.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/support/luhnCheck.ts b/test/support/luhnCheck.ts index b8fff49fadc..0f9d2c1c154 100644 --- a/test/support/luhnCheck.ts +++ b/test/support/luhnCheck.ts @@ -1,7 +1,5 @@ export function luhnCheck(ccNumber: string): boolean { - if (ccNumber.includes('-')) { - ccNumber = ccNumber.replace(/-/g, ''); - } + ccNumber = ccNumber.replace(/-/g, ''); let sum = 0; let alternate = false; for (let i = ccNumber.length - 1; i >= 0; i--) { From 1567d3dabad38fc5d9259538e99773883d7c0000 Mon Sep 17 00:00:00 2001 From: Eric Cheng Date: Sat, 21 May 2022 12:08:35 -0400 Subject: [PATCH 3/9] test: account for possible whitespace in ccNumber --- test/support/luhnCheck.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/support/luhnCheck.ts b/test/support/luhnCheck.ts index 0f9d2c1c154..04d9b541ea2 100644 --- a/test/support/luhnCheck.ts +++ b/test/support/luhnCheck.ts @@ -1,5 +1,5 @@ export function luhnCheck(ccNumber: string): boolean { - ccNumber = ccNumber.replace(/-/g, ''); + ccNumber = ccNumber.replace(/\s+/g, '').replace(/-/g, ''); let sum = 0; let alternate = false; for (let i = ccNumber.length - 1; i >= 0; i--) { From 1e477bc323eab19854e3b2661d51e7cb08a26b20 Mon Sep 17 00:00:00 2001 From: Eric Cheng Date: Mon, 23 May 2022 13:36:29 -0400 Subject: [PATCH 4/9] fix: working checkBit function --- src/modules/helpers/index.ts | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index 386bcce89eb..a5d9bb83d7b 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -1,4 +1,5 @@ import type { Faker } from '../..'; +import { luhnCheck } from '../../../test/support/luhnCheck'; /** * Module with various helper methods that transform the method input rather than returning values from locales. @@ -142,29 +143,21 @@ export class Helpers { // default values required for calling method without arguments // Function calculating the Luhn checksum of a number string - const getCheckBit = (number: number[]) => { - number.reverse(); - number = number.map((num, index) => { - if (index % 2 === 0) { - num *= 2; - if (num > 9) { - num -= 9; - } - } - return num; - }); - const sum = number.reduce((prev, curr) => prev + curr); - return sum % 10; + const getCheckBit = (string: string) => { + let checkBit = 0; + while ( + !luhnCheck(string.substring(0, string.length - 1) + String(checkBit)) + ) { + checkBit++; + string = string.substring(0, string.length - 1) + String(checkBit); + } + return checkBit; }; string = this.regexpStyleStringParse(string); // replace [4-9] with a random number in range etc... string = this.replaceSymbolWithNumber(string, symbol); // replace ### with random numbers - const numberList = string - .replace(/\D/g, '') - .split('') - .map((num) => parseInt(num)); - const checkNum = getCheckBit(numberList); + const checkNum = getCheckBit(string); return string.replace('L', String(checkNum)); } From 01f5ba9d13aa3398a7da3b761b9ffd80f563eb81 Mon Sep 17 00:00:00 2001 From: Eric Cheng Date: Mon, 23 May 2022 13:42:26 -0400 Subject: [PATCH 5/9] fix: rootDir error --- src/modules/helpers/index.ts | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index a5d9bb83d7b..5ec61dea2ec 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -1,5 +1,4 @@ import type { Faker } from '../..'; -import { luhnCheck } from '../../../test/support/luhnCheck'; /** * Module with various helper methods that transform the method input rather than returning values from locales. @@ -142,11 +141,33 @@ export class Helpers { ): string { // default values required for calling method without arguments + /** + * Luhn validator function. + * + * @param ccNumber The credit card number to validate. + */ + function luhnTester(ccNumber: string): boolean { + ccNumber = ccNumber.replace(/\s+/g, '').replace(/-/g, ''); + let sum = 0; + let alternate = false; + for (let i = ccNumber.length - 1; i >= 0; i--) { + let n = parseInt(ccNumber.substring(i, i + 1)); + if (alternate) { + n *= 2; + if (n > 9) { + n = (n % 10) + 1; + } + } + sum += n; + alternate = !alternate; + } + return sum % 10 === 0; + } // Function calculating the Luhn checksum of a number string const getCheckBit = (string: string) => { let checkBit = 0; while ( - !luhnCheck(string.substring(0, string.length - 1) + String(checkBit)) + !luhnTester(string.substring(0, string.length - 1) + String(checkBit)) ) { checkBit++; string = string.substring(0, string.length - 1) + String(checkBit); From 1e610d668c2c1263e44d606b48548a4427480038 Mon Sep 17 00:00:00 2001 From: Eric Cheng Date: Mon, 23 May 2022 13:36:29 -0400 Subject: [PATCH 6/9] fix: working checkBit function fix: rootDir error --- src/modules/helpers/index.ts | 48 +++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index 386bcce89eb..5ec61dea2ec 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -141,30 +141,44 @@ export class Helpers { ): string { // default values required for calling method without arguments - // Function calculating the Luhn checksum of a number string - const getCheckBit = (number: number[]) => { - number.reverse(); - number = number.map((num, index) => { - if (index % 2 === 0) { - num *= 2; - if (num > 9) { - num -= 9; + /** + * Luhn validator function. + * + * @param ccNumber The credit card number to validate. + */ + function luhnTester(ccNumber: string): boolean { + ccNumber = ccNumber.replace(/\s+/g, '').replace(/-/g, ''); + let sum = 0; + let alternate = false; + for (let i = ccNumber.length - 1; i >= 0; i--) { + let n = parseInt(ccNumber.substring(i, i + 1)); + if (alternate) { + n *= 2; + if (n > 9) { + n = (n % 10) + 1; } } - return num; - }); - const sum = number.reduce((prev, curr) => prev + curr); - return sum % 10; + sum += n; + alternate = !alternate; + } + return sum % 10 === 0; + } + // Function calculating the Luhn checksum of a number string + const getCheckBit = (string: string) => { + let checkBit = 0; + while ( + !luhnTester(string.substring(0, string.length - 1) + String(checkBit)) + ) { + checkBit++; + string = string.substring(0, string.length - 1) + String(checkBit); + } + return checkBit; }; string = this.regexpStyleStringParse(string); // replace [4-9] with a random number in range etc... string = this.replaceSymbolWithNumber(string, symbol); // replace ### with random numbers - const numberList = string - .replace(/\D/g, '') - .split('') - .map((num) => parseInt(num)); - const checkNum = getCheckBit(numberList); + const checkNum = getCheckBit(string); return string.replace('L', String(checkNum)); } From 6abe3cb2eb26473df9856e08d1b8f615f67ddbf5 Mon Sep 17 00:00:00 2001 From: Eric Cheng Date: Mon, 23 May 2022 13:52:20 -0400 Subject: [PATCH 7/9] test: Luhn tests --- test/finance.spec.ts | 6 +++--- test/helpers.spec.ts | 6 +++--- test/phone.spec.ts | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/finance.spec.ts b/test/finance.spec.ts index 0e19aa53542..49c2c52a826 100644 --- a/test/finance.spec.ts +++ b/test/finance.spec.ts @@ -19,7 +19,7 @@ const seedRuns = [ currencySymbol: '₱', bitcoinAddress: '3XbJMAAara64sSkA9HD24YHQWd1b', litecoinAddress: '3XbJMAAara64sSkA9HD24YHQWd1b', - creditCardNumber: '3581-7755-1410-0486', + creditCardNumber: '3581-7755-1410-0484', creditCardCVV: '379', pin: '3791', ethereumAddress: '0x8be4abdd39321ad7d3fe01ffce404f4d6db0906b', @@ -43,7 +43,7 @@ const seedRuns = [ currencySymbol: '$', bitcoinAddress: '3adhxs2jewAgkYgJi7No6Cn8JZa', litecoinAddress: 'Madhxs2jewAgkYgJi7No6Cn8JZar', - creditCardNumber: '6011-6212-2540-3255-2392', + creditCardNumber: '6011-6212-2540-3255-2398', creditCardCVV: '251', pin: '2512', ethereumAddress: '0x5c346ba075bd57f5a62b82d72af39cbbb07a98cb', @@ -67,7 +67,7 @@ const seedRuns = [ currencySymbol: '₭', bitcoinAddress: '1TMe8Z3EaFdLqmaGKP1LEEJQVriSZRZdsA', litecoinAddress: 'MTMe8Z3EaFdLqmaGKP1LEEJQVriSZRZds', - creditCardNumber: '4872190616276', + creditCardNumber: '4872190616274', creditCardCVV: '948', pin: '9487', ethereumAddress: '0xeadb42f0e3f4a973fab0aeefce96dfcf49cd438d', diff --git a/test/helpers.spec.ts b/test/helpers.spec.ts index 155d2d97efd..915da777e4d 100644 --- a/test/helpers.spec.ts +++ b/test/helpers.spec.ts @@ -9,7 +9,7 @@ const seededRuns = [ slugify: '', replaceSymbolWithNumber: '', replaceSymbols: '', - replaceCreditCardSymbols: '6453-3791-7755-1410-0481', + replaceCreditCardSymbols: '6453-3791-7755-1410-0489', repeatString: '', regexpStyleStringParse: '', shuffle: [], @@ -23,7 +23,7 @@ const seededRuns = [ slugify: '', replaceSymbolWithNumber: '', replaceSymbols: '', - replaceCreditCardSymbols: '6453-2512-2540-3255-2391', + replaceCreditCardSymbols: '6453-2512-2540-3255-2399', repeatString: '', regexpStyleStringParse: '', shuffle: [], @@ -37,7 +37,7 @@ const seededRuns = [ slugify: '', replaceSymbolWithNumber: '', replaceSymbols: '', - replaceCreditCardSymbols: '6453-9487-2190-6162-7436', + replaceCreditCardSymbols: '6453-9487-2190-6162-7434', repeatString: '', regexpStyleStringParse: '', shuffle: [], diff --git a/test/phone.spec.ts b/test/phone.spec.ts index 17180156008..7b6325df299 100644 --- a/test/phone.spec.ts +++ b/test/phone.spec.ts @@ -35,7 +35,7 @@ const seededRuns = [ noArgs: '(!##) !##-####', }, imei: { - noArgs: '25-122540-325523-6', + noArgs: '25-122540-325523-4', }, }, }, @@ -53,7 +53,7 @@ const seededRuns = [ noArgs: '1-!##-!##-#### x#####', }, imei: { - noArgs: '94-872190-616274-6', + noArgs: '94-872190-616274-4', }, }, }, From 367dea8592bbed9406fd32449a58ab5a569e0894 Mon Sep 17 00:00:00 2001 From: Shinigami92 Date: Mon, 23 May 2022 22:16:21 +0200 Subject: [PATCH 8/9] chore: move luhncheck function --- src/modules/helpers/index.ts | 25 ++----------------- .../modules/helpers/luhn-check.ts | 5 ++++ test/finance.spec.ts | 2 +- test/helpers.spec.ts | 2 +- test/phone.spec.ts | 2 +- 5 files changed, 10 insertions(+), 26 deletions(-) rename test/support/luhnCheck.ts => src/modules/helpers/luhn-check.ts (81%) diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index 5ec61dea2ec..46a3aec5fd8 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -1,4 +1,5 @@ import type { Faker } from '../..'; +import { luhnCheck } from './luhn-check'; /** * Module with various helper methods that transform the method input rather than returning values from locales. @@ -141,33 +142,11 @@ export class Helpers { ): string { // default values required for calling method without arguments - /** - * Luhn validator function. - * - * @param ccNumber The credit card number to validate. - */ - function luhnTester(ccNumber: string): boolean { - ccNumber = ccNumber.replace(/\s+/g, '').replace(/-/g, ''); - let sum = 0; - let alternate = false; - for (let i = ccNumber.length - 1; i >= 0; i--) { - let n = parseInt(ccNumber.substring(i, i + 1)); - if (alternate) { - n *= 2; - if (n > 9) { - n = (n % 10) + 1; - } - } - sum += n; - alternate = !alternate; - } - return sum % 10 === 0; - } // Function calculating the Luhn checksum of a number string const getCheckBit = (string: string) => { let checkBit = 0; while ( - !luhnTester(string.substring(0, string.length - 1) + String(checkBit)) + !luhnCheck(string.substring(0, string.length - 1) + String(checkBit)) ) { checkBit++; string = string.substring(0, string.length - 1) + String(checkBit); diff --git a/test/support/luhnCheck.ts b/src/modules/helpers/luhn-check.ts similarity index 81% rename from test/support/luhnCheck.ts rename to src/modules/helpers/luhn-check.ts index 04d9b541ea2..c5c8d2c3efe 100644 --- a/test/support/luhnCheck.ts +++ b/src/modules/helpers/luhn-check.ts @@ -1,3 +1,8 @@ +/** + * Luhn validator function. + * + * @param ccNumber The credit card number to validate. + */ export function luhnCheck(ccNumber: string): boolean { ccNumber = ccNumber.replace(/\s+/g, '').replace(/-/g, ''); let sum = 0; diff --git a/test/finance.spec.ts b/test/finance.spec.ts index 49c2c52a826..ef3fb045d72 100644 --- a/test/finance.spec.ts +++ b/test/finance.spec.ts @@ -2,7 +2,7 @@ import { afterEach, describe, expect, it } from 'vitest'; import { faker } from '../src'; import { FakerError } from '../src/errors/faker-error'; import ibanLib from '../src/modules/finance/iban'; -import { luhnCheck } from './support/luhnCheck'; +import { luhnCheck } from '../src/modules/helpers/luhn-check'; const seedRuns = [ { diff --git a/test/helpers.spec.ts b/test/helpers.spec.ts index 915da777e4d..f5f4e96f8ff 100644 --- a/test/helpers.spec.ts +++ b/test/helpers.spec.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, it } from 'vitest'; import { faker } from '../src'; -import { luhnCheck } from './support/luhnCheck'; +import { luhnCheck } from '../src/modules/helpers/luhn-check'; const seededRuns = [ { diff --git a/test/phone.spec.ts b/test/phone.spec.ts index 7b6325df299..e0ff1996fa2 100644 --- a/test/phone.spec.ts +++ b/test/phone.spec.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it } from 'vitest'; import { faker } from '../src'; -import { luhnCheck } from './support/luhnCheck'; +import { luhnCheck } from '../src/modules/helpers/luhn-check'; const seededRuns = [ { From 8432a0c771e45e381426590d4d68ea3b53bf4e7b Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Mon, 23 May 2022 22:55:05 +0200 Subject: [PATCH 9/9] chore: calculate luhn value instead of trying them all --- src/modules/helpers/index.ts | 16 ++------------- src/modules/helpers/luhn-check.ts | 34 ++++++++++++++++++++++++------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index 46a3aec5fd8..44750cb0e0a 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -1,5 +1,5 @@ import type { Faker } from '../..'; -import { luhnCheck } from './luhn-check'; +import { luhnCheckValue } from './luhn-check'; /** * Module with various helper methods that transform the method input rather than returning values from locales. @@ -142,22 +142,10 @@ export class Helpers { ): string { // default values required for calling method without arguments - // Function calculating the Luhn checksum of a number string - const getCheckBit = (string: string) => { - let checkBit = 0; - while ( - !luhnCheck(string.substring(0, string.length - 1) + String(checkBit)) - ) { - checkBit++; - string = string.substring(0, string.length - 1) + String(checkBit); - } - return checkBit; - }; - string = this.regexpStyleStringParse(string); // replace [4-9] with a random number in range etc... string = this.replaceSymbolWithNumber(string, symbol); // replace ### with random numbers - const checkNum = getCheckBit(string); + const checkNum = luhnCheckValue(string); return string.replace('L', String(checkNum)); } diff --git a/src/modules/helpers/luhn-check.ts b/src/modules/helpers/luhn-check.ts index c5c8d2c3efe..9cfcc577798 100644 --- a/src/modules/helpers/luhn-check.ts +++ b/src/modules/helpers/luhn-check.ts @@ -1,14 +1,34 @@ /** - * Luhn validator function. + * Checks that the given string passes the luhn algorithm. * - * @param ccNumber The credit card number to validate. + * @param str The string to validate. */ -export function luhnCheck(ccNumber: string): boolean { - ccNumber = ccNumber.replace(/\s+/g, '').replace(/-/g, ''); +export function luhnCheck(str: string): boolean { + return luhnChecksum(str) === 0; +} + +/** + * Calculates the luhn check value for the given string. + * + * @param str The string to calculate the check value for. + * May contain the `L` placeholder at the end. + */ +export function luhnCheckValue(str: string): number { + const checksum = luhnChecksum(str.replace(/L?$/, '0')); + return checksum === 0 ? 0 : 10 - checksum; +} + +/** + * Calculates the luhn checksum value for the given value. + * + * @param str The string to generate the checksum for. + */ +function luhnChecksum(str: string): number { + str = str.replace(/[\s-]/g, ''); let sum = 0; let alternate = false; - for (let i = ccNumber.length - 1; i >= 0; i--) { - let n = parseInt(ccNumber.substring(i, i + 1)); + for (let i = str.length - 1; i >= 0; i--) { + let n = parseInt(str.substring(i, i + 1)); if (alternate) { n *= 2; if (n > 9) { @@ -18,5 +38,5 @@ export function luhnCheck(ccNumber: string): boolean { sum += n; alternate = !alternate; } - return sum % 10 === 0; + return sum % 10; }