diff options
Diffstat (limited to 'test-internals.c')
-rw-r--r-- | test-internals.c | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/test-internals.c b/test-internals.c new file mode 100644 index 0000000..0ccd0de --- /dev/null +++ b/test-internals.c @@ -0,0 +1,145 @@ + +/* Internal tests that cannot be run against the library without unnecessary export of symbols. + Copyright (c) 2017, Perlbotics / see LICENSE.txt + */ + + +#include "zxcvbn.h" +/* need access to internals for testing; not linked against library, just inlined */ +#include "zxcvbn.c" + + +/********************************************************************************** + * Internal checks: Validate if the first element of each group is sorted in + * ascending order. CharBinSearch(...) fails otherwise. + * Returns 0 on success. + * Returns element index [1..] of first error entry that is less than previous one. + */ +static int check_order(const uint8_t *Ents, unsigned int NumEnts, unsigned int SizeEnts) { + const uint8_t *last; + unsigned int i; + + if (!Ents) return 0; + last = 0; + + for (i = 0; i < NumEnts; ++i, Ents += SizeEnts) { + if (last && *last > *Ents) { + unsigned int j; + + printf("Entry#%d [%d]: '%c' > '%c' (0x%02X > 0x%02X)\n A: ", i, i * SizeEnts, *last, *Ents, *last, *Ents); + for (j = 0; j < SizeEnts; ++j) { + printf("'%c' ", last[j] ? last[j] : ' '); + } + printf("\n >\n B: "); + for (j = 0; j < SizeEnts; ++j) { + printf("'%c' ", Ents[j] ? Ents[j] : ' '); + } + printf("\n"); + + return i; + } + last = Ents; + } + + return 0; /* cannot be a misordered position; first possible one: 1 */ +} + +/********************************************************************************** + * Internal checks: Checks keyboard data integrity. + * Returns 0 on succes. + * Otherwise, number of errors are reported. + */ +static unsigned int selftest_keyboards() { + unsigned int errors; + const Keyboard_t *k; + unsigned int Indx; + const uint8_t *keys; + int i,j,errpos, blanks; + + errors = 0; + for(k = Keyboards, Indx = 0; Indx < (sizeof Keyboards / sizeof Keyboards[0]); ++Indx, ++k) { + /* if one of these assrtion fails, we cannot use binary search algorithm */ + if (k->Shifts && strlen((const char*)k->Shifts) % 2 == 1) { + printf("ERROR: Keyboard[%d]: Shifts-string has odd number of entries.\n", Indx); + ++errors; + } + + if ( (errpos = check_order(k->Shifts, k->NumShift, 2)) ) { + printf("ERROR: Keyboard[%d]: Error above in sort order of Shifts-string near item #%d.\n", Indx, errpos); + ++errors; + } + + if ( (errpos = check_order(k->Keys, k->NumKeys, k->NumNear)) ) { + printf("ERROR: Keyboard[%d]: Error above in sort order of keyboard-entries! Problem near item #%d.\n", Indx, errpos); + ++errors; + continue; + } + + /* For each key (c0), check all its neighbours (ci): + * Does the neighbour key (c1==ci) have an entry (cx) in the opposite direction [rev_idx] + * pointing back to the current key c0? + * c0: ...ci.. --> c1: ..cx... --> cx==c0? + */ + keys = k->Keys; + blanks = 0; + for(i = 0; i < k->NumKeys; ++i) { + uint8_t c0; + c0 = keys[i * k->NumNear]; + + for (j = 0; j < k->NumNear - 1; ++j) { + const uint8_t *c1; + uint8_t ci, cx; + int rev_idx; + + /* rev_idx: reverse/opposite index to find opposite key location [0..6|8] --> [0..6|8] */ + rev_idx = (j + (k->NumNear - 1)/2) % (k->NumNear - 1); + ci = keys[i * k->NumNear + j + 1]; + + if (ci) { + c1 = CharBinSearch(ci, keys, k->NumKeys, k->NumNear); + if (c1) { + if (ci == c0) { + printf("ERROR: Keyboard[%d]: recursion - key '%c' cannot be its own neighbour!\n", Indx, *c1); + ++errors; + } else { + if ( (cx = c1[ 1 + rev_idx ]) ) { + if ( cx != c0 ) { + printf("ERROR: Keyboard[%d]: c0='%c':...(ci=%c)... -> c1='%c':...(cx=%c)... --!--> c0='%c':... \n", + Indx, c0, ci, *c1, cx, c0); + ++errors; + } + } else { /* reverse pointer is NULL */ + printf("ERROR: Keyboard[%d]: reverse entry missing in row c1='%c'[%d] pointing back to c0='%c'!\n", Indx, *c1, 1+rev_idx, c0); + ++errors; + } + } + } else { + printf("ERROR: Keyboard[%d]: no entry (neighbour list) found for src-char c1==ci='%c'\n", Indx, ci); + ++errors; + } + } else { /* blank neighbour key reference found */ + ++blanks; + } + } + } + if (blanks != k->NumBlank) { + printf("ERROR: Keyboard[%d]: number of blank keys announced (%d) does not match number of blank keys counted (%d)!\n", + Indx, k->NumBlank, blanks); + ++errors; + } + } + return errors; +} + + + + +int main() { + unsigned int errors; + + if( (errors = selftest_keyboards()) ){ /* currently only these */ + printf("FAILED: [KEYBOARDS] - selftest returned %d error(s).\n", errors); + } + + return errors ? 1 : 0; +} |