// File: ridiculousfish[P]docopt_fish/docopt_fish_test.cpp
// Function: test_fuzzing()
void test_fuzzing() {
    const char *tokens[] =
    {
        "--foo",
        "bar",
        "<baz>",
        "[options]",
        "...",
        ",",
        "  ",
        "Usage:",
        "Options:",
        "Arguments:",
        "[",
        "]",
        "(",
        ")",
        "|",
        "="
    };
    string_t storage;
    std::vector<doc_error_t> errors;
    const uint32_t token_count = sizeof tokens / sizeof *tokens;
    const uint32_t max_fuzz = 4; //could be raised up to 6 at the cost of some slowdown
    unsigned max_permutation = 1;
    for (uint32_t tokens_in_string=0; tokens_in_string <= max_fuzz; tokens_in_string++) {
        for (uint32_t permutation = 0; permutation < max_permutation; permutation++) {
            // Construct 'storage'
            storage.clear();
            errors.clear();
            uint32_t perm_cursor = permutation;
            for (size_t i=0; i < tokens_in_string; i++) {
                size_t token_idx = perm_cursor % token_count;
                perm_cursor /= token_count;
                if (i > 0) storage.push_back(' ');
                storage.insert(storage.end(), tokens[token_idx], tokens[token_idx] + strlen(tokens[token_idx]));
            }
            
            // Try to parse it
            // We should not crash or loop forever, and either parser should be non-nullptr or we should have an error
            argument_parser_t parser;
            bool parsed = parser.set_doc(storage, &errors);
            if (! parsed && errors.empty()) {
                err("No error generated for fuzz string '%ls'\n", wide(storage));
            }
        }
        // The next time around, we will have token_count times more permutations
        max_permutation *= token_count;
        //fprintf(stderr, "Fuzzed %u / %u\n", tokens_in_string, max_fuzz);
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x160, %rsp            # imm = 0x160
leaq -0x80(%rbp), %rdi
leaq 0x3517a(%rip), %rsi     # 0x703d0
movl $0x80, %edx
callq 0x8270
leaq -0xa0(%rbp), %rdi
callq 0x8150
leaq -0xb8(%rbp), %rdi
callq 0xbe50
movl $0x10, -0xbc(%rbp)
movl $0x4, -0xc0(%rbp)
movl $0x1, -0xc4(%rbp)
movl $0x0, -0xc8(%rbp)
cmpl $0x4, -0xc8(%rbp)
ja 0x3b525
movl $0x0, -0xcc(%rbp)
movl -0xcc(%rbp), %eax
cmpl -0xc4(%rbp), %eax
jae 0x3b502
leaq -0xa0(%rbp), %rdi
callq 0x83e0
leaq -0xb8(%rbp), %rdi
callq 0x43fd0
movl -0xcc(%rbp), %eax
movl %eax, -0xd0(%rbp)
movq $0x0, -0xd8(%rbp)
movq -0xd8(%rbp), %rax
movl -0xc8(%rbp), %ecx
cmpq %rcx, %rax
jae 0x3b3f8
movl -0xd0(%rbp), %eax
andl $0xf, %eax
movl %eax, %eax
movq %rax, -0xe0(%rbp)
movl -0xd0(%rbp), %eax
shrl $0x4, %eax
movl %eax, -0xd0(%rbp)
cmpq $0x0, -0xd8(%rbp)
jbe 0x3b365
leaq -0xa0(%rbp), %rdi
movl $0x20, %esi
callq 0x80d0
jmp 0x3b34c
jmp 0x3b365
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xe8(%rbp)
movl %eax, -0xec(%rbp)
jmp 0x3b546
leaq -0xa0(%rbp), %rdi
movq %rdi, -0x150(%rbp)
callq 0x84f0
movq %rax, -0x100(%rbp)
leaq -0xf8(%rbp), %rdi
leaq -0x100(%rbp), %rsi
callq 0x2c200
movq -0xe0(%rbp), %rax
movq -0x80(%rbp,%rax,8), %rdi
movq %rdi, -0x148(%rbp)
callq 0x8110
movq -0x150(%rbp), %rdi
movq -0x148(%rbp), %rdx
movq %rdx, %rcx
addq %rax, %rcx
movq -0xf8(%rbp), %rsi
callq 0x43ff0
movq %rax, -0x140(%rbp)
jmp 0x3b3d3
movq -0x140(%rbp), %rax
movq %rax, -0x108(%rbp)
movq -0xd8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xd8(%rbp)
jmp 0x3b2f8
leaq -0x110(%rbp), %rdi
callq 0xab20
jmp 0x3b406
leaq -0x138(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0x82c0
jmp 0x3b41b
leaq -0x110(%rbp), %rdi
leaq -0x138(%rbp), %rsi
leaq -0xb8(%rbp), %rdx
callq 0xa910
movb %al, -0x151(%rbp)
jmp 0x3b43d
leaq -0x138(%rbp), %rdi
callq 0x8590
movb -0x151(%rbp), %al
andb $0x1, %al
movb %al, -0x111(%rbp)
testb $0x1, -0x111(%rbp)
jne 0x3b4d4
leaq -0xb8(%rbp), %rdi
callq 0xbfd0
testb $0x1, %al
jne 0x3b472
jmp 0x3b4d4
leaq -0xa0(%rbp), %rdi
callq 0x3b6c0
movq %rax, -0x160(%rbp)
jmp 0x3b487
movq -0x160(%rbp), %rsi
leaq 0x1169a(%rip), %rdi     # 0x4cb2f
xorl %eax, %eax
callq 0x3b570
jmp 0x3b49e
jmp 0x3b4d4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xe8(%rbp)
movl %eax, -0xec(%rbp)
jmp 0x3b4f4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xe8(%rbp)
movl %eax, -0xec(%rbp)
leaq -0x138(%rbp), %rdi
callq 0x8590
jmp 0x3b4f4
leaq -0x110(%rbp), %rdi
callq 0xac20
movl -0xcc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xcc(%rbp)
jmp 0x3b2b7
leaq -0x110(%rbp), %rdi
callq 0xac20
jmp 0x3b546
movl -0xc4(%rbp), %eax
shll $0x4, %eax
movl %eax, -0xc4(%rbp)
movl -0xc8(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xc8(%rbp)
jmp 0x3b2a0
leaq -0xb8(%rbp), %rdi
callq 0xc3d0
leaq -0xa0(%rbp), %rdi
callq 0x8590
addq $0x160, %rsp            # imm = 0x160
popq %rbp
retq
leaq -0xb8(%rbp), %rdi
callq 0xc3d0
leaq -0xa0(%rbp), %rdi
callq 0x8590
movq -0xe8(%rbp), %rdi
callq 0x85d0
nopw (%rax,%rax)