LCOV - code coverage report
Current view: top level - src/tests - markov.c (source / functions) Hit Total Coverage
Test: passgen-test.info Lines: 216 216 100.0 %
Date: 2024-05-03 06:05:14 Functions: 11 11 100.0 %

          Line data    Source code
       1             : #include "passgen/markov.h"
       2             : #include "tests.h"
       3             : #include <stdlib.h>
       4             : 
       5             : #define SEED 234720984723
       6             : 
       7             : #define passgen_markov_leaf_count_raw(leaf, codepoint) \
       8             :     leaf->entries[leaf->capacity].count[codepoint % leaf->capacity]
       9             : 
      10             : #define passgen_markov_leaf_codepoint_raw(leaf, index) \
      11             :     leaf->entries[0].codepoint[index % leaf->capacity]
      12             : 
      13           1 : test_result test_markov_node_layout(void) {
      14           1 :     passgen_markov_node *node = passgen_markov_node_new(0);
      15             : 
      16           1 :     assert_eq(node->capacity, 3);
      17             : 
      18             :     assert_eq(
      19             :         &passgen_markov_node_codepoint(node, 0),
      20             :         ((void *) node) + sizeof(size_t));
      21           1 :     assert_eq(
      22             :         &passgen_markov_node_codepoint(node, 1),
      23             :         ((void *) node) + sizeof(size_t) + 1 * sizeof(uint32_t));
      24           1 :     assert_eq(
      25             :         &passgen_markov_node_codepoint(node, 2),
      26             :         ((void *) node) + sizeof(size_t) + 2 * sizeof(uint32_t));
      27             : 
      28           1 :     assert_eq(
      29             :         &passgen_markov_node_child(node, 0),
      30             :         ((void *) node) + sizeof(size_t) + 4 * sizeof(uint32_t));
      31           1 :     assert_eq(
      32             :         &passgen_markov_node_child(node, 1),
      33             :         ((void *) node) + 2 * sizeof(size_t) + 4 * sizeof(uint32_t));
      34           1 :     assert_eq(
      35             :         &passgen_markov_node_child(node, 2),
      36             :         ((void *) node) + 3 * sizeof(size_t) + 4 * sizeof(uint32_t));
      37             : 
      38           1 :     free(node);
      39             : 
      40           1 :     return test_ok;
      41             : }
      42             : 
      43           1 : test_result test_markov_leaf_layout(void) {
      44           1 :     passgen_markov_leaf *leaf = passgen_markov_leaf_new(0);
      45             : 
      46           1 :     assert_eq(leaf->capacity, 3);
      47             : 
      48             :     assert_eq(
      49             :         &passgen_markov_leaf_codepoint_raw(leaf, 0),
      50             :         ((void *) leaf) + 2 * sizeof(size_t));
      51           1 :     assert_eq(
      52             :         &passgen_markov_leaf_codepoint_raw(leaf, 1),
      53             :         ((void *) leaf) + 2 * sizeof(size_t) + 1 * sizeof(uint32_t));
      54           1 :     assert_eq(
      55             :         &passgen_markov_leaf_codepoint_raw(leaf, 2),
      56             :         ((void *) leaf) + 2 * sizeof(size_t) + 2 * sizeof(uint32_t));
      57             : 
      58           1 :     assert_eq(
      59             :         &passgen_markov_leaf_count_raw(leaf, 0),
      60             :         ((void *) leaf) + 2 * sizeof(size_t) + 3 * sizeof(uint32_t));
      61           1 :     assert_eq(
      62             :         &passgen_markov_leaf_count_raw(leaf, 1),
      63             :         ((void *) leaf) + 2 * sizeof(size_t) + 4 * sizeof(uint32_t));
      64           1 :     assert_eq(
      65             :         &passgen_markov_leaf_count_raw(leaf, 2),
      66             :         ((void *) leaf) + 2 * sizeof(size_t) + 5 * sizeof(uint32_t));
      67             : 
      68           1 :     free(leaf);
      69             : 
      70           1 :     return test_ok;
      71             : }
      72             : 
      73           1 : test_result test_markov_node_insert(void) {
      74           1 :     passgen_markov_node *node = passgen_markov_node_new(0);
      75           1 :     assert_eq(node->capacity, 3);
      76             : 
      77           1 :     node = passgen_markov_node_insert(node, 0);
      78           1 :     assert(!passgen_markov_node_child(node, 0).node);
      79           1 :     passgen_markov_node_child(node, 0).node = (passgen_markov_node *) &node;
      80             : 
      81           1 :     node = passgen_markov_node_insert(node, 1);
      82           1 :     assert(!passgen_markov_node_child(node, 1).node);
      83           1 :     passgen_markov_node_child(node, 1).node = (passgen_markov_node *) &node;
      84             : 
      85           1 :     node = passgen_markov_node_insert(node, 2);
      86           1 :     assert(!passgen_markov_node_child(node, 2).node);
      87           1 :     passgen_markov_node_child(node, 2).node = (passgen_markov_node *) &node;
      88             : 
      89           1 :     assert_eq(node->capacity, 3);
      90             : 
      91           1 :     node = passgen_markov_node_insert(node, 3);
      92           1 :     assert(!passgen_markov_node_child(node, 3).node);
      93           1 :     passgen_markov_node_child(node, 3).node = (passgen_markov_node *) &node;
      94             : 
      95           1 :     assert_eq(node->capacity, 7);
      96             : 
      97           1 :     node = passgen_markov_node_insert(node, 4);
      98           1 :     assert(!passgen_markov_node_child(node, 4).node);
      99           1 :     passgen_markov_node_child(node, 4).node = (passgen_markov_node *) &node;
     100             : 
     101           1 :     node = passgen_markov_node_insert(node, 5);
     102           1 :     assert(!passgen_markov_node_child(node, 5).node);
     103           1 :     passgen_markov_node_child(node, 5).node = (passgen_markov_node *) &node;
     104             : 
     105           1 :     node = passgen_markov_node_insert(node, 6);
     106           1 :     assert(!passgen_markov_node_child(node, 6).node);
     107           1 :     passgen_markov_node_child(node, 6).node = (passgen_markov_node *) &node;
     108             : 
     109           1 :     node = passgen_markov_node_insert(node, 7);
     110           1 :     assert(!passgen_markov_node_child(node, 7).node);
     111           1 :     passgen_markov_node_child(node, 7).node = (passgen_markov_node *) &node;
     112             : 
     113           1 :     assert_eq(node->capacity, 17);
     114             : 
     115         993 :     for(size_t i = 8; i < 1000; i++) {
     116         992 :         node = passgen_markov_node_insert(node, i);
     117         992 :         assert(!passgen_markov_node_child(node, i).node);
     118         992 :         passgen_markov_node_child(node, i).node = (passgen_markov_node *) &node;
     119             :     }
     120             : 
     121           1 :     assert_eq(node->capacity, 1361);
     122             : 
     123           1 :     free(node);
     124             : 
     125           1 :     return test_ok;
     126             : }
     127             : 
     128           1 : test_result test_markov_leaf_insert(void) {
     129           1 :     passgen_markov_leaf *leaf = passgen_markov_leaf_new(0);
     130           1 :     assert_eq(leaf->capacity, 3);
     131             : 
     132           1 :     leaf = passgen_markov_leaf_insert(leaf, 0, 1);
     133           1 :     assert(passgen_markov_leaf_count_raw(leaf, 0) == 1);
     134             : 
     135           1 :     leaf = passgen_markov_leaf_insert(leaf, 0, 1);
     136           1 :     assert(passgen_markov_leaf_count_raw(leaf, 0) == 2);
     137             : 
     138           1 :     leaf = passgen_markov_leaf_insert(leaf, 1, 3);
     139           1 :     assert(passgen_markov_leaf_count_raw(leaf, 1) == 3);
     140             : 
     141           1 :     leaf = passgen_markov_leaf_insert(leaf, 2, 7);
     142           1 :     assert(passgen_markov_leaf_count_raw(leaf, 2) == 7);
     143             : 
     144           1 :     assert_eq(leaf->capacity, 3);
     145             : 
     146           1 :     leaf = passgen_markov_leaf_insert(leaf, 3, 2);
     147           1 :     assert(passgen_markov_leaf_count_raw(leaf, 3) == 2);
     148             : 
     149           1 :     assert_eq(leaf->capacity, 7);
     150             : 
     151           1 :     leaf = passgen_markov_leaf_insert(leaf, 4, 4);
     152           1 :     assert(passgen_markov_leaf_count_raw(leaf, 4) == 4);
     153             : 
     154           1 :     leaf = passgen_markov_leaf_insert(leaf, 5, 6);
     155           1 :     assert(passgen_markov_leaf_count_raw(leaf, 5) == 6);
     156             : 
     157           1 :     leaf = passgen_markov_leaf_insert(leaf, 6, 8);
     158           1 :     assert(passgen_markov_leaf_count_raw(leaf, 6) == 8);
     159             : 
     160           1 :     leaf = passgen_markov_leaf_insert(leaf, 7, 10);
     161           1 :     assert(passgen_markov_leaf_count_raw(leaf, 7) == 10);
     162             : 
     163           1 :     assert_eq(leaf->capacity, 17);
     164             : 
     165         993 :     for(size_t i = 8; i < 1000; i++) {
     166         992 :         leaf = passgen_markov_leaf_insert(leaf, i, i);
     167         992 :         assert(passgen_markov_leaf_count_raw(leaf, i) == i);
     168             :     }
     169             : 
     170           1 :     assert_eq(leaf->capacity, 1361);
     171             : 
     172           1 :     free(leaf);
     173             : 
     174           1 :     return test_ok;
     175             : }
     176             : 
     177           1 : test_result test_markov_node_insert_word(void) {
     178           1 :     passgen_markov_node *root_node = passgen_markov_node_new(0);
     179             : 
     180           1 :     const uint32_t word[] = {'h', 'e', 'l', 'l', 'o'};
     181             : 
     182             :     root_node =
     183           1 :         passgen_markov_node_insert_word(root_node, (void *) &word, 5, 1);
     184           1 :     passgen_markov_node *node = root_node;
     185             : 
     186           1 :     assert_eq(passgen_markov_node_codepoint(node, 'h'), 'h');
     187           1 :     node = passgen_markov_node_child(node, 'h').node;
     188           1 :     assert(node);
     189             : 
     190           1 :     assert_eq(passgen_markov_node_codepoint(node, 'e'), 'e');
     191           1 :     node = passgen_markov_node_child(node, 'e').node;
     192           1 :     assert(node);
     193             : 
     194           1 :     assert_eq(passgen_markov_node_codepoint(node, 'l'), 'l');
     195           1 :     node = passgen_markov_node_child(node, 'l').node;
     196           1 :     assert(node);
     197             : 
     198           1 :     assert_eq(passgen_markov_node_codepoint(node, 'l'), 'l');
     199           1 :     passgen_markov_leaf *leaf = passgen_markov_node_child(node, 'l').leaf;
     200           1 :     assert(leaf);
     201           1 :     assert_eq(leaf->capacity, 3);
     202           1 :     assert_eq(leaf->total_count, 1);
     203             : 
     204           1 :     assert_eq(passgen_markov_leaf_codepoint_raw(leaf, 'o'), 'o');
     205           1 :     assert_eq(passgen_markov_leaf_count_raw(leaf, 'o'), 1);
     206             : 
     207           1 :     passgen_markov_node_free(root_node, 4);
     208             : 
     209           1 :     return test_ok;
     210             : }
     211             : 
     212           1 : test_result test_markov_add(void) {
     213             :     passgen_markov markov;
     214             :     passgen_markov_node *node;
     215             :     passgen_markov_leaf *leaf;
     216             : 
     217             :     // markov chain level 2, meaning two prefix chars
     218           1 :     passgen_markov_init(&markov, 2);
     219             : 
     220             :     // this should have added 00a and 0a0 into the chain.
     221           1 :     passgen_markov_add(&markov, (void *) &(const uint32_t[]){'a'}, 1, 1);
     222             : 
     223             :     // verify 00a is there
     224           1 :     node = passgen_markov_node_child(markov.root, 0).node;
     225           1 :     assert(node);
     226           1 :     leaf = passgen_markov_node_child(node, 0).leaf;
     227           1 :     assert(leaf);
     228           1 :     assert_eq(leaf->total_count, 1);
     229           1 :     assert_eq(passgen_markov_leaf_codepoint_raw(leaf, 'a'), 'a');
     230           1 :     assert_eq(passgen_markov_leaf_count_raw(leaf, 'a'), 1);
     231             : 
     232             :     // verify 0a0 is there
     233           1 :     node = passgen_markov_node_child(markov.root, 0).node;
     234           1 :     assert(node);
     235           1 :     leaf = passgen_markov_node_child(node, 'a').leaf;
     236           1 :     assert(leaf);
     237           1 :     assert_eq(leaf->total_count, 1);
     238           1 :     assert_eq(passgen_markov_leaf_codepoint_raw(leaf, 0), 0);
     239           1 :     assert_eq(passgen_markov_leaf_count_raw(leaf, 0), 1);
     240             : 
     241             :     // this should have added 00l, 0la, la0, each with a weight of 2.
     242           1 :     passgen_markov_add(&markov, (void *) &(const uint32_t[]){'l', 'a'}, 2, 2);
     243             : 
     244             :     // verify 00l is there
     245           1 :     node = passgen_markov_node_child(markov.root, 0).node;
     246           1 :     assert(node);
     247           1 :     leaf = passgen_markov_node_child(node, 0).leaf;
     248           1 :     assert(leaf);
     249           1 :     assert_eq(leaf->total_count, 3);
     250           1 :     assert_eq(passgen_markov_leaf_codepoint_raw(leaf, 'l'), 'l');
     251           1 :     assert_eq(passgen_markov_leaf_count_raw(leaf, 'l'), 2);
     252             : 
     253             :     // verify 0la is there
     254           1 :     node = passgen_markov_node_child(markov.root, 0).node;
     255           1 :     assert(node);
     256           1 :     leaf = passgen_markov_node_child(node, 'l').leaf;
     257           1 :     assert(leaf);
     258           1 :     assert_eq(leaf->total_count, 2);
     259           1 :     assert_eq(passgen_markov_leaf_codepoint_raw(leaf, 'a'), 'a');
     260           1 :     assert_eq(passgen_markov_leaf_count_raw(leaf, 'a'), 2);
     261             : 
     262             :     // verify la0 is there
     263           1 :     node = passgen_markov_node_child(markov.root, 'l').node;
     264           1 :     assert(node);
     265           1 :     leaf = passgen_markov_node_child(node, 'a').leaf;
     266           1 :     assert(leaf);
     267           1 :     assert_eq(leaf->total_count, 2);
     268           1 :     assert_eq(passgen_markov_leaf_codepoint_raw(leaf, 0), 0);
     269           1 :     assert_eq(passgen_markov_leaf_count_raw(leaf, 0), 2);
     270             : 
     271           1 :     passgen_markov_add(&markov, (void *) &(const uint32_t[]){'l', 'e'}, 2, 1);
     272           1 :     passgen_markov_add(
     273             :         &markov,
     274           1 :         (void *) &(const uint32_t[]){'t', 'h', 'e'},
     275             :         3,
     276             :         1);
     277           1 :     passgen_markov_add(
     278             :         &markov,
     279           1 :         (void *) &(const uint32_t[]){'p', 'a', 'r', 't'},
     280             :         4,
     281             :         1);
     282           1 :     passgen_markov_add(
     283             :         &markov,
     284           1 :         (void *) &(const uint32_t[]){'p', 'h', 'o', 'n', 'e'},
     285             :         5,
     286             :         1);
     287             : 
     288           1 :     passgen_markov_free(&markov);
     289             : 
     290           1 :     return test_ok;
     291             : }
     292             : 
     293           1 : test_result test_markov_add_random(void) {
     294             :     passgen_markov markov;
     295             :     passgen_random rand;
     296           1 :     passgen_random_open_xorshift(&rand, SEED);
     297           1 :     uint32_t word[12] = {0};
     298             : 
     299           8 :     for(size_t length = 3; length < 10; length++) {
     300           7 :         passgen_markov_init(&markov, length);
     301             : 
     302             :         // FIXME: if you set count to 1000, it breaks.
     303         707 :         for(size_t count = 0; count < 100; count++) {
     304        9100 :             for(size_t offset = 0; offset < 12; offset++) {
     305        8400 :                 word[offset] = passgen_random_u32(&rand);
     306             :             }
     307             : 
     308         700 :             passgen_markov_add(&markov, &word[0], 12, 1);
     309             :         }
     310             : 
     311           7 :         passgen_markov_free(&markov);
     312             :     }
     313             : 
     314           1 :     passgen_random_close(&rand);
     315             : 
     316           1 :     return test_ok;
     317             : }
     318             : 
     319           1 : test_result test_markov_leaf_count_random(void) {
     320             :     passgen_random rand;
     321           1 :     passgen_random_open_xorshift(&rand, SEED);
     322           1 :     passgen_markov_leaf *leaf = passgen_markov_leaf_new(0);
     323             : 
     324             :     /// FIXME: if you 10x the count, it breaks.
     325        1001 :     for(size_t count = 0; count < 1000; count++) {
     326        1000 :         uint32_t codepoint = passgen_random_u32(&rand);
     327        1000 :         uint32_t before = passgen_markov_leaf_count(leaf, codepoint);
     328        1000 :         assert_eq(before, 0);
     329             :     }
     330             : 
     331           1 :     passgen_markov_leaf_free(leaf);
     332           1 :     passgen_random_close(&rand);
     333             : 
     334           1 :     return test_ok;
     335             : }
     336             : 
     337           1 : test_result test_markov_leaf_insert_random(void) {
     338             :     passgen_random rand;
     339           1 :     passgen_random_open_xorshift(&rand, SEED);
     340           1 :     passgen_markov_leaf *leaf = passgen_markov_leaf_new(0);
     341             : 
     342       10001 :     for(size_t count = 0; count < 10000; count++) {
     343       10000 :         uint32_t codepoint = passgen_random_u32(&rand);
     344       10000 :         uint32_t weight = passgen_random_u16(&rand);
     345       10000 :         uint32_t before = passgen_markov_leaf_count(leaf, codepoint);
     346       10000 :         leaf = passgen_markov_leaf_insert(leaf, codepoint, weight);
     347       10000 :         uint32_t after = passgen_markov_leaf_count(leaf, codepoint);
     348       10000 :         assert_eq(after - before, weight);
     349             :     }
     350             : 
     351           1 :     passgen_markov_leaf_free(leaf);
     352           1 :     passgen_random_close(&rand);
     353             : 
     354           1 :     return test_ok;
     355             : }
     356             : 
     357           1 : test_result test_markov_leaf_insert_sequential(void) {
     358             :     passgen_random rand;
     359           1 :     passgen_random_open_xorshift(&rand, SEED);
     360           1 :     passgen_markov_leaf *leaf = passgen_markov_leaf_new(0);
     361             : 
     362      100001 :     for(size_t count = 0; count < 100000; count++) {
     363      100000 :         uint32_t codepoint = count;
     364      100000 :         uint32_t weight = passgen_random_u16(&rand);
     365      100000 :         uint32_t before = passgen_markov_leaf_count(leaf, codepoint);
     366      100000 :         leaf = passgen_markov_leaf_insert(leaf, codepoint, weight);
     367      100000 :         uint32_t after = passgen_markov_leaf_count(leaf, codepoint);
     368      100000 :         assert_eq(after - before, weight);
     369             :     }
     370             : 
     371           1 :     passgen_markov_leaf_free(leaf);
     372           1 :     passgen_random_close(&rand);
     373             : 
     374           1 :     return test_ok;
     375             : }
     376             : 
     377           1 : test_result test_markov_generate(void) {
     378           1 :     passgen_random *rand = passgen_random_new_xorshift(SEED);
     379             :     // passgen_random_open_xorshift(&rand, SEED);
     380             : 
     381             :     passgen_markov markov;
     382           1 :     passgen_markov_init(&markov, 2);
     383             : 
     384           1 :     passgen_markov_add(&markov, &(const uint32_t[]){'a', 'b'}[0], 2, 1);
     385           1 :     passgen_markov_add(&markov, &(const uint32_t[]){'b'}[0], 1, 1);
     386           1 :     passgen_markov_add(
     387             :         &markov,
     388           1 :         &(const uint32_t[]){'c', 'd', 'e', 'f'}[0],
     389             :         4,
     390             :         1);
     391             : 
     392             :     /*
     393             :     uint32_t next, word[32];
     394             :     memset(word, 0, sizeof(word));
     395             : 
     396             :     word[2] = passgen_markov_generate(&markov, &word[0], rand);
     397             :     assert(word[2] == 'c');
     398             :     word[3] = passgen_markov_generate(&markov, &word[1], rand);
     399             :     assert(word[3] == 'd');
     400             :     word[4] = passgen_markov_generate(&markov, &word[2], rand);
     401             :     assert(word[4] == 'e');
     402             :     word[5] = passgen_markov_generate(&markov, &word[3], rand);
     403             :     assert(word[5] == 'f');
     404             :     word[6] = passgen_markov_generate(&markov, &word[4], rand);
     405             :     assert(word[6] == 0);
     406             : 
     407             :     word[2] = passgen_markov_generate(&markov, &word[0], rand);
     408             :     assert(word[2] == 'b');
     409             :     word[3] = passgen_markov_generate(&markov, &word[1], rand);
     410             :     assert(word[3] == 0);
     411             :     */
     412             : 
     413           1 :     passgen_markov_free(&markov);
     414           1 :     passgen_random_free(rand);
     415             : 
     416           1 :     return test_ok;
     417             : }

Generated by: LCOV version 1.14