mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
0.2.0 LUHN
This commit is contained in:
parent
56083a3b85
commit
43f55d1eaa
@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
|||||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
|
||||||
|
## [0.2.0] - 2023-05-08
|
||||||
|
- add unit test
|
||||||
|
- fix stream mode - **add()** and **reset()**
|
||||||
|
- fix bugs in generation / validation.
|
||||||
|
- add **generateChecksum(const char \* buffer)**
|
||||||
|
- change **count** to be 32 bit to support really large streams.
|
||||||
|
- add **count()** function to return internal counter.
|
||||||
|
- updates readme.md
|
||||||
|
- 0.1.x versions are obsolete
|
||||||
|
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
## [0.1.1] - 2022-12-29
|
## [0.1.1] - 2022-12-29
|
||||||
- add stream interface
|
- add stream interface
|
||||||
- **char add(char c)**
|
- **char add(char c)**
|
||||||
@ -14,6 +27,5 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- update documentation
|
- update documentation
|
||||||
- fix warning
|
- fix warning
|
||||||
|
|
||||||
|
|
||||||
## [0.1.0] - 2022-12-24
|
## [0.1.0] - 2022-12-24
|
||||||
- initial version
|
- initial version
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// FILE: LUHN.cpp
|
// FILE: LUHN.cpp
|
||||||
// AUTHOR: Rob Tillaart
|
// AUTHOR: Rob Tillaart
|
||||||
// VERSION: 0.1.1
|
// VERSION: 0.2.0
|
||||||
// DATE: 2022-12-24
|
// DATE: 2022-12-24
|
||||||
// PURPOSE: Arduino Library for calculating LUHN checksum.
|
// PURPOSE: Arduino Library for calculating LUHN checksum.
|
||||||
// URL: https://github.com/RobTillaart/LUHN
|
// URL: https://github.com/RobTillaart/LUHN
|
||||||
@ -12,7 +12,8 @@
|
|||||||
|
|
||||||
LUHN::LUHN()
|
LUHN::LUHN()
|
||||||
{
|
{
|
||||||
_luhn = 0;
|
_luhnEven = 0;
|
||||||
|
_luhnOdd = 0;
|
||||||
_count = 0;
|
_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,10 +30,11 @@ bool LUHN::isValid(char * buffer)
|
|||||||
uint8_t length = strlen(buffer);
|
uint8_t length = strlen(buffer);
|
||||||
if (length == 0) return false;
|
if (length == 0) return false;
|
||||||
|
|
||||||
|
uint8_t parity = length & 1;
|
||||||
for (int i = 0; i < length-1; i++)
|
for (int i = 0; i < length-1; i++)
|
||||||
{
|
{
|
||||||
uint8_t x = buffer[i] - '0';
|
uint8_t x = buffer[i] - '0';
|
||||||
if (i % 2 == 0) checksum += x; // weight 1
|
if (i % 2 != parity) checksum += x; // weight 1
|
||||||
else if (x < 5) checksum += x * 2; // weight 2
|
else if (x < 5) checksum += x * 2; // weight 2
|
||||||
else checksum += (x * 2 - 10 + 1); // weight 2 + handle overflow.
|
else checksum += (x * 2 - 10 + 1); // weight 2 + handle overflow.
|
||||||
}
|
}
|
||||||
@ -42,14 +44,21 @@ bool LUHN::isValid(char * buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char LUHN::generateChecksum(const char * buffer)
|
||||||
|
{
|
||||||
|
return generateChecksum((char *) buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
char LUHN::generateChecksum(char * buffer)
|
char LUHN::generateChecksum(char * buffer)
|
||||||
{
|
{
|
||||||
uint16_t checksum = 0;
|
uint16_t checksum = 0;
|
||||||
uint8_t length = strlen(buffer);
|
uint8_t length = strlen(buffer);
|
||||||
|
uint8_t parity = length & 1;
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
uint8_t x = buffer[i] - '0';
|
uint8_t x = buffer[i] - '0';
|
||||||
if (i % 2 == 0) checksum += x; // weight 1
|
if (i % 2 == parity) checksum += x; // weight 1
|
||||||
else if (x < 5) checksum += x * 2; // weight 2
|
else if (x < 5) checksum += x * 2; // weight 2
|
||||||
else checksum += (x * 2 - 10 + 1); // weight 2 + handle overflow.
|
else checksum += (x * 2 - 10 + 1); // weight 2 + handle overflow.
|
||||||
}
|
}
|
||||||
@ -83,25 +92,44 @@ bool LUHN::generate(char * buffer, uint8_t length, char * prefix)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// STREAM INTERFACE
|
||||||
|
//
|
||||||
char LUHN::add(char c)
|
char LUHN::add(char c)
|
||||||
{
|
{
|
||||||
|
// as we do not know the final length in advance
|
||||||
|
// both parity's must be calculated.
|
||||||
uint8_t x = c - '0';
|
uint8_t x = c - '0';
|
||||||
if (_count % 2 == 0) _luhn += x;
|
// handle even lengths
|
||||||
else if (x < 5) _luhn += x * 2;
|
if (_count % 2 == 0) _luhnEven += x;
|
||||||
else _luhn += (x * 2 - 10 + 1);
|
else if (x < 5) _luhnEven += x * 2;
|
||||||
// correct
|
else _luhnEven += (x * 2 - 10 + 1);
|
||||||
if (_luhn > 9) _luhn -= 10;
|
// handle odd lengths
|
||||||
|
if (_count % 2 == 1) _luhnOdd += x;
|
||||||
|
else if (x < 5) _luhnOdd += x * 2;
|
||||||
|
else _luhnOdd += (x * 2 - 10 + 1);
|
||||||
|
|
||||||
_count++;
|
_count++;
|
||||||
return '0' + (10 - _luhn);
|
if (_count & 1) return '0' + (100 - _luhnOdd) % 10;
|
||||||
|
return '0' + (100 - _luhnEven) % 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char LUHN::reset()
|
char LUHN::reset()
|
||||||
{
|
{
|
||||||
uint8_t last = _luhn;
|
uint8_t last = _luhnEven;
|
||||||
_luhn = 0;
|
if (_count & 1) last = _luhnOdd;
|
||||||
|
_luhnEven = 0;
|
||||||
|
_luhnOdd = 0;
|
||||||
_count = 0;
|
_count = 0;
|
||||||
return '0' + (10 - last);
|
return '0' + (100 - last) % 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t LUHN::count()
|
||||||
|
{
|
||||||
|
return _count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -125,5 +153,25 @@ uint8_t LUHN::Marsaglia_mod10()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// EXPERIMENTAL
|
||||||
|
// ~8% faster and 58 bytes bigger (UNO)
|
||||||
|
// uint8_t LUHN::Marsaglia_mod10()
|
||||||
|
// {
|
||||||
|
// static uint32_t value;
|
||||||
|
// static uint8_t digits = 0;
|
||||||
|
// if (digits == 0)
|
||||||
|
// {
|
||||||
|
// digits = 4;
|
||||||
|
// m_z = 36969L * (m_z & 65535L) + (m_z >> 16);
|
||||||
|
// m_w = 18000L * (m_w & 65535L) + (m_w >> 16);
|
||||||
|
// value = (m_z ^ m_w);
|
||||||
|
// }
|
||||||
|
// uint8_t rv = value % 10;
|
||||||
|
// value >>= 8;
|
||||||
|
// digits--;
|
||||||
|
// return rv;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
// -- END OF FILE --
|
// -- END OF FILE --
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
//
|
//
|
||||||
// FILE: LUHN.h
|
// FILE: LUHN.h
|
||||||
// AUTHOR: Rob Tillaart
|
// AUTHOR: Rob Tillaart
|
||||||
// VERSION: 0.1.1
|
// VERSION: 0.2.0
|
||||||
// DATE: 2022-12-24
|
// DATE: 2022-12-24
|
||||||
// PURPOSE: Arduino Library for calculating LUHN checksum.
|
// PURPOSE: Arduino Library for calculating LUHN checksum.
|
||||||
// URL: https://github.com/RobTillaart/LUHN
|
// URL: https://github.com/RobTillaart/LUHN
|
||||||
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
|
|
||||||
#define LUHN_LIB_VERSION (F("0.1.1"))
|
#define LUHN_LIB_VERSION (F("0.2.0"))
|
||||||
|
|
||||||
|
|
||||||
class LUHN
|
class LUHN
|
||||||
@ -22,6 +22,7 @@ public:
|
|||||||
// buffer == \0 terminated
|
// buffer == \0 terminated
|
||||||
bool isValid(const char * buffer);
|
bool isValid(const char * buffer);
|
||||||
bool isValid(char * buffer);
|
bool isValid(char * buffer);
|
||||||
|
char generateChecksum(const char * buffer);
|
||||||
char generateChecksum(char * buffer);
|
char generateChecksum(char * buffer);
|
||||||
|
|
||||||
// GENERATE A PRODUCT ID WITH LUHN CHECKSUM
|
// GENERATE A PRODUCT ID WITH LUHN CHECKSUM
|
||||||
@ -31,15 +32,16 @@ public:
|
|||||||
// STREAM INTERFACE
|
// STREAM INTERFACE
|
||||||
char add(char c);
|
char add(char c);
|
||||||
char reset();
|
char reset();
|
||||||
|
uint32_t count();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint32_t m_w = 1; // random generator parameter
|
uint32_t m_w = 1; // random generator parameter
|
||||||
uint32_t m_z = 2; // random generator parameter
|
uint32_t m_z = 2; // random generator parameter
|
||||||
uint8_t Marsaglia_mod10();
|
uint8_t Marsaglia_mod10();
|
||||||
|
|
||||||
uint8_t _luhn = 0;
|
uint16_t _luhnEven = 0;
|
||||||
uint16_t _count = 0;
|
uint16_t _luhnOdd = 0;
|
||||||
|
uint32_t _count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,13 +20,28 @@ The LUHN check uses very few resources and is pretty fast.
|
|||||||
|
|
||||||
Basic idea is to put all digits-1 through the formula and the output should equal the last digit.
|
Basic idea is to put all digits-1 through the formula and the output should equal the last digit.
|
||||||
|
|
||||||
Note: some LUHN validations uses the reversed product string.
|
This LUHN library also includes a "stream" based LUHN calculation, in which digits can be add
|
||||||
|
one at a time (from a stream) and it will return the LUHN checksum so far.
|
||||||
|
This is a new application as LUHN depends on the length of the input being odd or even.
|
||||||
|
To handle this two values are maintained (for odd and even lengths) and the correct one is returned.
|
||||||
|
|
||||||
|
Maintaining two checksums makes the stream **add(c)** algorithm substantial slower (~4x) than
|
||||||
|
the normally used **generateChecksum(buffer)** or the **isValid(buffer)**.
|
||||||
|
However that is a small price for the new functionality.
|
||||||
|
|
||||||
|
The amount of data that can be added in stream mode is infinite in theory.
|
||||||
|
However that is not tested for obvious reasons, internally a 32 bit counter exists.
|
||||||
|
|
||||||
|
|
||||||
|
#### Notes
|
||||||
|
|
||||||
|
- some LUHN validations uses the reversed product string.
|
||||||
|
- 0.1.x versions are obsolete due to incorrect math.
|
||||||
|
|
||||||
|
|
||||||
|
#### Links
|
||||||
|
|
||||||
- https://en.wikipedia.org/wiki/Luhn_algorithm
|
- https://en.wikipedia.org/wiki/Luhn_algorithm
|
||||||
|
|
||||||
|
|
||||||
#### related
|
|
||||||
|
|
||||||
- https://github.com/RobTillaart/Adler
|
- https://github.com/RobTillaart/Adler
|
||||||
- https://github.com/RobTillaart/CRC
|
- https://github.com/RobTillaart/CRC
|
||||||
- https://github.com/RobTillaart/Fletcher
|
- https://github.com/RobTillaart/Fletcher
|
||||||
@ -46,6 +61,7 @@ The parameter buffer is a '\0' terminated char array. Length should be less than
|
|||||||
- **char generateChecksum(char \* buffer)**
|
- **char generateChecksum(char \* buffer)**
|
||||||
Returns the char '0'..'9' which is the checksum of the code in the parameter buffer.
|
Returns the char '0'..'9' which is the checksum of the code in the parameter buffer.
|
||||||
The parameter buffer is a '\0' terminated char array. Length should be less than 254.
|
The parameter buffer is a '\0' terminated char array. Length should be less than 254.
|
||||||
|
- **char generateChecksum(const char \* buffer)** idem.
|
||||||
- **bool generate(char \* buffer, uint8_t length, char \* prefix)**
|
- **bool generate(char \* buffer, uint8_t length, char \* prefix)**
|
||||||
Generates a char array including LUHN number with a defined prefix of max length.
|
Generates a char array including LUHN number with a defined prefix of max length.
|
||||||
Returns false if the prefix exceeds length -1.
|
Returns false if the prefix exceeds length -1.
|
||||||
@ -53,26 +69,37 @@ Returns false if the prefix exceeds length -1.
|
|||||||
|
|
||||||
#### Stream
|
#### Stream
|
||||||
|
|
||||||
- **char add(char c)** add char, return LUHN so far.
|
- **char add(char c)** add char, returns LUHN so far.
|
||||||
- **char reset()** return last LUHN.
|
- **char reset()** return last LUHN.
|
||||||
|
- **uint32_t count()** return internal counter.
|
||||||
|
If this value is zero, a new LUHN can be calculated, otherwise call **reset()** first.
|
||||||
|
|
||||||
|
The internal counter for the stream interface is 32 bit.
|
||||||
|
This limits the number of add() calls to about 4 billion.
|
||||||
|
For current implementation the counter is used for even/odd detection,
|
||||||
|
and even when it overflows one gets the correct **LUHN**.
|
||||||
|
|
||||||
The internal counter for the stream interface is 16 bit.
|
|
||||||
This limits the nr of add() calls to about 65530.
|
|
||||||
(if this is a problem, make it an uinit32_t)
|
|
||||||
|
|
||||||
## Future
|
## Future
|
||||||
|
|
||||||
#### must
|
#### Must
|
||||||
|
|
||||||
- update documentation
|
|
||||||
|
|
||||||
#### should
|
#### Should
|
||||||
|
|
||||||
- unit tests
|
- look for optimizations
|
||||||
- look for optimization
|
|
||||||
|
|
||||||
#### could
|
#### Could
|
||||||
|
|
||||||
|
|
||||||
|
#### Won't (unless)
|
||||||
|
|
||||||
|
- create a HEX equivalent of LUHN
|
||||||
|
- LUHN16 ?
|
||||||
|
- easy to enter HEX code with verify / line.
|
||||||
|
- mod N configurable so not only 10 but any N?
|
||||||
|
- uint64_t interface for up to 17 digits.
|
||||||
|
- expensive on small processors.
|
||||||
- uint32_t interface for up to 8 digit ID's (99.999.999)
|
- uint32_t interface for up to 8 digit ID's (99.999.999)
|
||||||
- **isValid(uint32_t)**
|
- **isValid(uint32_t)**
|
||||||
- **generateChecksum(uint32_t)**
|
- **generateChecksum(uint32_t)**
|
||||||
|
@ -23,6 +23,8 @@ void setup()
|
|||||||
while (!Serial);
|
while (!Serial);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
Serial.println(__FILE__);
|
Serial.println(__FILE__);
|
||||||
|
Serial.print("LUHN_LIB_VERSION: ");
|
||||||
|
Serial.println(LUHN_LIB_VERSION);
|
||||||
|
|
||||||
// SHOULD PRINT 3
|
// SHOULD PRINT 3
|
||||||
Serial.println(checker.generateChecksum((char *)"7992739871"));
|
Serial.println(checker.generateChecksum((char *)"7992739871"));
|
||||||
|
@ -24,8 +24,10 @@ void setup()
|
|||||||
while (!Serial);
|
while (!Serial);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
Serial.println(__FILE__);
|
Serial.println(__FILE__);
|
||||||
|
Serial.print("LUHN_LIB_VERSION: ");
|
||||||
|
Serial.println(LUHN_LIB_VERSION);
|
||||||
|
|
||||||
Serial.println("run I: debug");
|
Serial.println("run I: add() per character");
|
||||||
for (uint8_t i = 0; i < strlen(ID) - 1; i++)
|
for (uint8_t i = 0; i < strlen(ID) - 1; i++)
|
||||||
{
|
{
|
||||||
c = checker.add(ID[i]);
|
c = checker.add(ID[i]);
|
||||||
@ -46,12 +48,45 @@ void setup()
|
|||||||
}
|
}
|
||||||
c = checker.reset();
|
c = checker.reset();
|
||||||
stop = micros();
|
stop = micros();
|
||||||
Serial.println();
|
Serial.print("LUHN:\t");
|
||||||
Serial.print("run II:\t");
|
Serial.println(c); // should print 3.
|
||||||
Serial.println(c); // should also print 3 .
|
Serial.print("time:\t");
|
||||||
Serial.print(" time:\t");
|
|
||||||
Serial.print(stop - start);
|
Serial.print(stop - start);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
delay(10);
|
||||||
|
|
||||||
|
Serial.println("run II: should have same 2nd column as run 1.");
|
||||||
|
for (uint8_t i = 0; i < strlen(ID); i++)
|
||||||
|
{
|
||||||
|
char tmp[32];
|
||||||
|
strcpy(tmp, ID);
|
||||||
|
tmp[i] = 0;
|
||||||
|
c = checker.generateChecksum(tmp);
|
||||||
|
Serial.print(tmp);
|
||||||
|
Serial.print("\t");
|
||||||
|
Serial.println(c);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
delay(10);
|
||||||
|
|
||||||
|
|
||||||
|
char tmp[32];
|
||||||
|
strcpy(tmp, ID);
|
||||||
|
tmp[strlen(ID)-1] = 0;
|
||||||
|
start = micros();
|
||||||
|
c = checker.generateChecksum(tmp);
|
||||||
|
stop = micros();
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("run III: generateChecksum()");
|
||||||
|
Serial.print("LUHN:\t");
|
||||||
|
Serial.println(c); // should print 3.
|
||||||
|
Serial.print("time:\t");
|
||||||
|
Serial.print(stop - start);
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
delay(10);
|
||||||
|
|
||||||
|
|
||||||
Serial.println("\ndone...");
|
Serial.println("\ndone...");
|
||||||
}
|
}
|
||||||
|
40
libraries/LUHN/examples/luhn_check_stream/output_0.2.0.txt
Normal file
40
libraries/LUHN/examples/luhn_check_stream/output_0.2.0.txt
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
Arduino UNO
|
||||||
|
IDE 1.8.19
|
||||||
|
|
||||||
|
luhn_check_stream.ino
|
||||||
|
LUHN_LIB_VERSION: 0.2.0
|
||||||
|
run I: add() per character
|
||||||
|
7 5
|
||||||
|
9 4
|
||||||
|
9 7
|
||||||
|
2 1
|
||||||
|
7 0
|
||||||
|
3 8
|
||||||
|
9 8
|
||||||
|
8 2
|
||||||
|
7 5
|
||||||
|
1 3
|
||||||
|
|
||||||
|
LUHN: 3
|
||||||
|
time: 256
|
||||||
|
|
||||||
|
run II: should have same 2nd column as run 1.
|
||||||
|
0
|
||||||
|
7 5
|
||||||
|
79 4
|
||||||
|
799 7
|
||||||
|
7992 1
|
||||||
|
79927 0
|
||||||
|
799273 8
|
||||||
|
7992739 8
|
||||||
|
79927398 2
|
||||||
|
799273987 5
|
||||||
|
7992739871 3
|
||||||
|
|
||||||
|
|
||||||
|
run III: generateChecksum()
|
||||||
|
LUHN: 3
|
||||||
|
time: 64
|
||||||
|
|
||||||
|
|
||||||
|
done...
|
@ -22,6 +22,10 @@ void setup()
|
|||||||
while (!Serial);
|
while (!Serial);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
Serial.println(__FILE__);
|
Serial.println(__FILE__);
|
||||||
|
Serial.print("LUHN_LIB_VERSION: ");
|
||||||
|
Serial.println(LUHN_LIB_VERSION);
|
||||||
|
Serial.println();
|
||||||
|
delay(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -35,7 +39,8 @@ void loop()
|
|||||||
Serial.print(checker.isValid(number));
|
Serial.print(checker.isValid(number));
|
||||||
Serial.print("\t");
|
Serial.print("\t");
|
||||||
Serial.print(stop - start);
|
Serial.print(stop - start);
|
||||||
// Serial.print((1.0*(stop - start))/ strlen(number)); per digit
|
Serial.print("\t");
|
||||||
|
Serial.print((1.0 * (stop - start)) / strlen(number)); // per digit
|
||||||
Serial.print("\t");
|
Serial.print("\t");
|
||||||
Serial.println(number);
|
Serial.println(number);
|
||||||
delay(100);
|
delay(100);
|
||||||
|
@ -11,6 +11,8 @@ generateChecksum KEYWORD2
|
|||||||
randomize KEYWORD2
|
randomize KEYWORD2
|
||||||
generate KEYWORD2
|
generate KEYWORD2
|
||||||
|
|
||||||
|
add KEYWORD2
|
||||||
|
reset KEYWORD2
|
||||||
|
|
||||||
# Constants (LITERAL1)
|
# Constants (LITERAL1)
|
||||||
LUHN_LIB_VERSION LITERAL1
|
LUHN_LIB_VERSION LITERAL1
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/RobTillaart/LUHN.git"
|
"url": "https://github.com/RobTillaart/LUHN.git"
|
||||||
},
|
},
|
||||||
"version": "0.1.1",
|
"version": "0.2.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"frameworks": "arduino",
|
"frameworks": "arduino",
|
||||||
"platforms": "*",
|
"platforms": "*",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name=LUHN
|
name=LUHN
|
||||||
version=0.1.1
|
version=0.2.0
|
||||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||||
sentence=Arduino Library for calculating LUHN checksum.
|
sentence=Arduino Library for calculating LUHN checksum.
|
||||||
|
131
libraries/LUHN/test/unit_test_001.cpp
Normal file
131
libraries/LUHN/test/unit_test_001.cpp
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
//
|
||||||
|
// FILE: unit_test_001.cpp
|
||||||
|
// AUTHOR: Rob Tillaart
|
||||||
|
// DATE: 2023-05-02
|
||||||
|
// PURPOSE: unit tests for the LUHN checksum
|
||||||
|
// https://github.com/RobTillaart/LUHN
|
||||||
|
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
|
||||||
|
//
|
||||||
|
|
||||||
|
// supported assertions
|
||||||
|
// ----------------------------
|
||||||
|
// assertEqual(expected, actual)
|
||||||
|
// assertNotEqual(expected, actual)
|
||||||
|
// assertLess(expected, actual)
|
||||||
|
// assertMore(expected, actual)
|
||||||
|
// assertLessOrEqual(expected, actual)
|
||||||
|
// assertMoreOrEqual(expected, actual)
|
||||||
|
// assertTrue(actual)
|
||||||
|
// assertFalse(actual)
|
||||||
|
// assertNull(actual)
|
||||||
|
|
||||||
|
|
||||||
|
#include <ArduinoUnitTests.h>
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include "LUHN.h"
|
||||||
|
|
||||||
|
|
||||||
|
unittest_setup()
|
||||||
|
{
|
||||||
|
fprintf(stderr, "LUHN_LIB_VERSION: %s\n", (char *) LUHN_LIB_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest_teardown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unittest(test_constructor)
|
||||||
|
{
|
||||||
|
LUHN luhn;
|
||||||
|
|
||||||
|
assertEqual('0', luhn.reset());
|
||||||
|
assertEqual('0', luhn.reset());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unittest(test_isValid)
|
||||||
|
{
|
||||||
|
LUHN luhn;
|
||||||
|
|
||||||
|
assertTrue(luhn.isValid("0"));
|
||||||
|
assertTrue(luhn.isValid("79927398713"));
|
||||||
|
assertTrue(luhn.isValid("1111111"));
|
||||||
|
assertTrue(luhn.isValid("11111111111111111111"));
|
||||||
|
|
||||||
|
// generated by https://www.dcode.fr/luhn-algorithm
|
||||||
|
assertTrue(luhn.isValid("08192186963920766401"));
|
||||||
|
|
||||||
|
|
||||||
|
// https://www.mobilefish.com/services/credit_card_number_generator/credit_card_number_generator.php
|
||||||
|
|
||||||
|
fprintf(stderr, "Example American Express credit card number\n");
|
||||||
|
// An American Express credit card number starts with number 34 or 37 and
|
||||||
|
// the credit card number has total 15 digits:
|
||||||
|
assertTrue(luhn.isValid("377261620324999"));
|
||||||
|
assertTrue(luhn.isValid("349854194206314"));
|
||||||
|
|
||||||
|
fprintf(stderr, "Example Mastercard credit card number\n");
|
||||||
|
// A Mastercard credit card number starts with number 51, 52, 53, 54 or 55 and
|
||||||
|
// the credit card number has total 16 digits:
|
||||||
|
assertTrue(luhn.isValid("5181975718047403"));
|
||||||
|
assertTrue(luhn.isValid("5204571199083364"));
|
||||||
|
assertTrue(luhn.isValid("5322683667269933"));
|
||||||
|
assertTrue(luhn.isValid("5477754834149242"));
|
||||||
|
assertTrue(luhn.isValid("5539624233693270"));
|
||||||
|
|
||||||
|
fprintf(stderr, "Example Laser credit card number\n");
|
||||||
|
// A Laser credit card number starts with number 6304, 6706, 6771 or 6709 and
|
||||||
|
// the credit card number has total 16, 17, 18 or 19 digits:
|
||||||
|
assertTrue(luhn.isValid("670676038979126821"));
|
||||||
|
assertTrue(luhn.isValid("6771363087405086"));
|
||||||
|
assertTrue(luhn.isValid("6304096514549839"));
|
||||||
|
assertTrue(luhn.isValid("6304219447607087665"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unittest(test_generateChecksum)
|
||||||
|
{
|
||||||
|
LUHN luhn;
|
||||||
|
|
||||||
|
assertEqual('3', luhn.generateChecksum("7992739871"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unittest(test_generate)
|
||||||
|
{
|
||||||
|
LUHN luhn;
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
char buffer[24];
|
||||||
|
char prefix[10] = "007";
|
||||||
|
assertTrue(luhn.generate(buffer, 20, prefix));
|
||||||
|
assertTrue(luhn.isValid(buffer));
|
||||||
|
fprintf(stderr, "%d %s\n", i, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unittest(test_stream)
|
||||||
|
{
|
||||||
|
LUHN luhn;
|
||||||
|
|
||||||
|
luhn.reset();
|
||||||
|
char buffer[24] = "7992739871";
|
||||||
|
for (int i = 0; i < strlen(buffer); i++)
|
||||||
|
{
|
||||||
|
char c = luhn.add(buffer[i]);
|
||||||
|
fprintf(stderr, "%d %c\n", i, c);
|
||||||
|
}
|
||||||
|
assertEqual('3', luhn.reset());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unittest_main()
|
||||||
|
|
||||||
|
|
||||||
|
// -- END OF FILE --
|
Loading…
Reference in New Issue
Block a user