#!/bin/sh
. $(dirname $(readlink -f $0))/framework.sh

# Check that building a single-byte trie works
testsuccessequal "\
┌────────────────────────────────────────────────────┐
│                   Initial trie                     │
└────────────────────────────────────────────────────┘

├── V
│   ├── e
│   │   ├── r
│   │   │   ├── y
│   │   │   │   ├── L
│   │   │   │   │   ├── o
│   │   │   │   │   │   ├── n
│   │   │   │   │   │   │   ├── g
│   │   │   │   │   │   │   │   ├── W
│   │   │   │   │   │   │   │   │   ├── o
│   │   │   │   │   │   │   │   │   │   ├── r
│   │   │   │   │   │   │   │   │   │   │   ├── d → VeryLongWord
├── W
│   ├── o
│   │   ├── r
│   │   │   ├── d → Word
│   │   │   │   ├── -
│   │   │   │   │   ├── _
│   │   │   │   │   │   ├── 0 → Word-_0
│   │   │   │   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│                   Rebuilt trie                     │
└────────────────────────────────────────────────────┘

├── V
│   ├── e
│   │   ├── r
│   │   │   ├── y
│   │   │   │   ├── L
│   │   │   │   │   ├── o
│   │   │   │   │   │   ├── n
│   │   │   │   │   │   │   ├── g
│   │   │   │   │   │   │   │   ├── W
│   │   │   │   │   │   │   │   │   ├── o
│   │   │   │   │   │   │   │   │   │   ├── r
│   │   │   │   │   │   │   │   │   │   │   ├── d → VeryLongWord
├── W
│   ├── o
│   │   ├── r
│   │   │   ├── d → Word
│   │   │   │   ├── -
│   │   │   │   │   ├── _
│   │   │   │   │   │   ├── 0 → Word-_0
│   │   │   │   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│              Trie for words of length 4            │
└────────────────────────────────────────────────────┘

├── W
│   ├── o
│   │   ├── r
│   │   │   ├── d → Word
┌────────────────────────────────────────────────────┐
│              Trie for words of length 5            │
└────────────────────────────────────────────────────┘

├── W
│   ├── o
│   │   ├── r
│   │   │   ├── d
│   │   │   │   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│              Trie for words of length 7            │
└────────────────────────────────────────────────────┘

├── W
│   ├── o
│   │   ├── r
│   │   │   ├── d
│   │   │   │   ├── -
│   │   │   │   │   ├── _
│   │   │   │   │   │   ├── 0 → Word-_0
┌────────────────────────────────────────────────────┐
│              Trie for words of length 12           │
└────────────────────────────────────────────────────┘

├── V
│   ├── e
│   │   ├── r
│   │   │   ├── y
│   │   │   │   ├── L
│   │   │   │   │   ├── o
│   │   │   │   │   │   ├── n
│   │   │   │   │   │   │   ├── g
│   │   │   │   │   │   │   │   ├── W
│   │   │   │   │   │   │   │   │   ├── o
│   │   │   │   │   │   │   │   │   │   ├── r
│   │   │   │   │   │   │   │   │   │   │   ├── d → VeryLongWord" triehash --multi-byte=0 -l tree /dev/stdin

# Two byte optimization
testsuccessequal "\
┌────────────────────────────────────────────────────┐
│                   Initial trie                     │
└────────────────────────────────────────────────────┘

├── Ve
│   ├── ry
│   │   ├── Lo
│   │   │   ├── ng
│   │   │   │   ├── Wo
│   │   │   │   │   ├── rd → VeryLongWord
├── Wo
│   ├── rd → Word
│   │   ├── -_
│   │   │   ├── 0 → Word-_0
│   │   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│                   Rebuilt trie                     │
└────────────────────────────────────────────────────┘

├── Ve
│   ├── ry
│   │   ├── Lo
│   │   │   ├── ng
│   │   │   │   ├── Wo
│   │   │   │   │   ├── rd → VeryLongWord
├── Wo
│   ├── rd → Word
│   │   ├── -
│   │   │   ├── _0 → Word-_0
│   │   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│              Trie for words of length 4            │
└────────────────────────────────────────────────────┘

├── Wo
│   ├── rd → Word
┌────────────────────────────────────────────────────┐
│              Trie for words of length 5            │
└────────────────────────────────────────────────────┘

├── Wo
│   ├── rd
│   │   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│              Trie for words of length 7            │
└────────────────────────────────────────────────────┘

├── Wo
│   ├── rd
│   │   ├── -_
│   │   │   ├── 0 → Word-_0
┌────────────────────────────────────────────────────┐
│              Trie for words of length 12           │
└────────────────────────────────────────────────────┘

├── Ve
│   ├── ry
│   │   ├── Lo
│   │   │   ├── ng
│   │   │   │   ├── Wo
│   │   │   │   │   ├── rd → VeryLongWord" triehash --multi-byte=1 -l tree /dev/stdin
# Four byte optimization
testsuccessequal "\
┌────────────────────────────────────────────────────┐
│                   Initial trie                     │
└────────────────────────────────────────────────────┘

├── Very
│   ├── Long
│   │   ├── Word → VeryLongWord
├── Word → Word
│   ├── -
│   │   ├── _
│   │   │   ├── 0 → Word-_0
│   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│                   Rebuilt trie                     │
└────────────────────────────────────────────────────┘

├── Very
│   ├── Long
│   │   ├── Word → VeryLongWord
├── Word → Word
│   ├── -
│   │   ├── _
│   │   │   ├── 0 → Word-_0
│   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│              Trie for words of length 4            │
└────────────────────────────────────────────────────┘

├── Word → Word
┌────────────────────────────────────────────────────┐
│              Trie for words of length 5            │
└────────────────────────────────────────────────────┘

├── Word
│   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│              Trie for words of length 7            │
└────────────────────────────────────────────────────┘

├── Word
│   ├── -
│   │   ├── _
│   │   │   ├── 0 → Word-_0
┌────────────────────────────────────────────────────┐
│              Trie for words of length 12           │
└────────────────────────────────────────────────────┘

├── Very
│   ├── Long
│   │   ├── Word → VeryLongWord" triehash --multi-byte=2 -l tree /dev/stdin
# Eigh byte optimization
testsuccessequal "\
┌────────────────────────────────────────────────────┐
│                   Initial trie                     │
└────────────────────────────────────────────────────┘

├── VeryLong
│   ├── W
│   │   ├── o
│   │   │   ├── r
│   │   │   │   ├── d → VeryLongWord
├── W
│   ├── o
│   │   ├── r
│   │   │   ├── d → Word
│   │   │   │   ├── -
│   │   │   │   │   ├── _
│   │   │   │   │   │   ├── 0 → Word-_0
│   │   │   │   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│                   Rebuilt trie                     │
└────────────────────────────────────────────────────┘

├── V
│   ├── eryLongW
│   │   ├── o
│   │   │   ├── r
│   │   │   │   ├── d → VeryLongWord
├── W
│   ├── o
│   │   ├── r
│   │   │   ├── d → Word
│   │   │   │   ├── -
│   │   │   │   │   ├── _
│   │   │   │   │   │   ├── 0 → Word-_0
│   │   │   │   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│              Trie for words of length 4            │
└────────────────────────────────────────────────────┘

├── W
│   ├── o
│   │   ├── r
│   │   │   ├── d → Word
┌────────────────────────────────────────────────────┐
│              Trie for words of length 5            │
└────────────────────────────────────────────────────┘

├── W
│   ├── o
│   │   ├── r
│   │   │   ├── d
│   │   │   │   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│              Trie for words of length 7            │
└────────────────────────────────────────────────────┘

├── W
│   ├── o
│   │   ├── r
│   │   │   ├── d
│   │   │   │   ├── -
│   │   │   │   │   ├── _
│   │   │   │   │   │   ├── 0 → Word-_0
┌────────────────────────────────────────────────────┐
│              Trie for words of length 12           │
└────────────────────────────────────────────────────┘

├── VeryLong
│   ├── W
│   │   ├── o
│   │   │   ├── r
│   │   │   │   ├── d → VeryLongWord" triehash --multi-byte=3 -l tree /dev/stdin


# Check that building a multi-byte trie works
testsuccessequal "\
┌────────────────────────────────────────────────────┐
│                   Initial trie                     │
└────────────────────────────────────────────────────┘

├── VeryLong
│   ├── Word → VeryLongWord
├── Word → Word
│   ├── -
│   │   ├── _
│   │   │   ├── 0 → Word-_0
│   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│                   Rebuilt trie                     │
└────────────────────────────────────────────────────┘

├── Very
│   ├── LongWord → VeryLongWord
├── Word → Word
│   ├── -
│   │   ├── _
│   │   │   ├── 0 → Word-_0
│   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│              Trie for words of length 4            │
└────────────────────────────────────────────────────┘

├── Word → Word
┌────────────────────────────────────────────────────┐
│              Trie for words of length 5            │
└────────────────────────────────────────────────────┘

├── Word
│   ├── 2 → Label
┌────────────────────────────────────────────────────┐
│              Trie for words of length 7            │
└────────────────────────────────────────────────────┘

├── Word
│   ├── -
│   │   ├── _
│   │   │   ├── 0 → Word-_0
┌────────────────────────────────────────────────────┐
│              Trie for words of length 12           │
└────────────────────────────────────────────────────┘

├── VeryLong
│   ├── Word → VeryLongWord" triehash -l tree /dev/stdin


###### CHANGE THE WORDS FOR THE FOLLOWING TESTS #######
WORDS="Word"

# Check that we are generating the proper multi-byte and fallback sessions
testsuccessequal "#include \"/dev/null\"
#ifdef __GNUC__
typedef uint16_t __attribute__((aligned (1))) triehash_uu16;
typedef char static_assert16[__alignof__(triehash_uu16) == 1 ? 1 : -1];
typedef uint32_t __attribute__((aligned (1))) triehash_uu32;
typedef char static_assert32[__alignof__(triehash_uu32) == 1 ? 1 : -1];
typedef uint64_t __attribute__((aligned (1))) triehash_uu64;
typedef char static_assert64[__alignof__(triehash_uu64) == 1 ? 1 : -1];
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define onechar(c, s, l) (((uint64_t)(c)) << (s))
#else
#define onechar(c, s, l) (((uint64_t)(c)) << (l-8-s))
#endif
#if (!defined(__ARM_ARCH) || defined(__ARM_FEATURE_UNALIGNED)) && !defined(TRIE_HASH_NO_MULTI_BYTE)
#define TRIE_HASH_MULTI_BYTE
#endif
#endif /*GNUC */
#ifdef TRIE_HASH_MULTI_BYTE
static enum PerfectKey PerfectHash4(const char *string)
{
    switch(*((triehash_uu32*) &string[0])) {
    case 0| onechar('W', 0, 32)| onechar('o', 8, 32)| onechar('r', 16, 32)| onechar('d', 24, 32):
        return Word;
    }
    return Unknown;
}
#else
static enum PerfectKey PerfectHash4(const char *string)
{
    switch(string[0]) {
    case 'W':
        switch(string[1]) {
        case 'o':
            switch(string[2]) {
            case 'r':
                switch(string[3]) {
                case 'd':
                    return Word;
                }
            }
        }
    }
    return Unknown;
}
#endif /* TRIE_HASH_MULTI_BYTE */
 enum PerfectKey PerfectHash(const char *string, size_t length)
{
    switch (length) {
    case 4:
        return PerfectHash4(string);
    default:
        return Unknown;
    }
}" triehash -H /dev/null /dev/stdin


# Check that we are generating no multi-byte session
testsuccessequal "#include \"/dev/null\"
static enum PerfectKey PerfectHash4(const char *string)
{
    switch(string[0]) {
    case 'W':
        switch(string[1]) {
        case 'o':
            switch(string[2]) {
            case 'r':
                switch(string[3]) {
                case 'd':
                    return Word;
                }
            }
        }
    }
    return Unknown;
}
 enum PerfectKey PerfectHash(const char *string, size_t length)
{
    switch (length) {
    case 4:
        return PerfectHash4(string);
    default:
        return Unknown;
    }
}" triehash --multi-byte=0 -H /dev/null /dev/stdin