Question: What encryption schemes do the tests cover?

Answer:
The test functions cover decryption of messages encrypted with various schemes, including:
- A1Z26 substitution cipher (test_a1z26)
- Affine cipher (test_affine)
- ASCII shift cipher (test_ascii_shift)
- Atbash cipher (test_atbash)
- Baconian cipher with complete and standard variants (test_baconian_complete_variant, test_baconian_standard_variant)
- Base32 (test_base32)
- Base58 with Bitcoin and Ripple alphabets (test_base58_bitcoin, test_base58_ripple)
- Base62 (test_base62)
- Base64 (test_base64)
- Base85 (test_base85)
- Base91 (test_base91)
- Baudot code (test_baudot)
- Binary ASCII (test_binary)
- Braille (test_braille)
- Brainfuck language (test_brainfuck)
- Caesar cipher (test_caesar)
- Decimal ASCII (test_decimal)
and many more. Each test function contains an encrypted string and checks that decrypt decodes it to the expected plaintext.

import pytest

from ciphey import decrypt
from ciphey.iface import Config

answer_str = "Hello my name is bee and I like dog and apple and tree"

def test_a1z26():
    res = decrypt(
        Config().library_default().complete_config(),
        "8 5 12 12 15 13 25 14 1 13 5 9 19 2 5 5 1 14 4 9 12 9 11 5 4 15 7 1 14 4 1 16 16 12 5 1 14 4 20 18 5 5",
    )
    assert res == "hellomynameisbeeandilikedogandappleandtree"

def test_affine():
    res = decrypt(
        Config().library_default().complete_config(),
        "Ihsst bf kxbh rd ghh xky R srjh ytz xky xccsh xky muhh",
    )
    assert res == answer_str

def test_ascii_shift():
    res = decrypt(
        Config().library_default().complete_config(),
        '"?FFIzGSzH;G?zCMz<??z;H>z#zFCE?z>IAz;H>z;JJF?z;H>zNL??',
    )
    assert res == answer_str

def test_atbash():
    res = decrypt(
        Config().library_default().complete_config(),
        "Svool nb mznv rh yvv zmw R orpv wlt zmw zkkov zmw givv",
    )
    assert res == answer_str

def test_baconian_complete_variant():
    res = decrypt(
        Config().library_default().complete_config(),
        "AABBB AABAA ABABB ABABB ABBBA ABBAA BBAAA ABBAB AAAAA ABBAA AABAA ABAAA BAABA AAAAB AABAA AABAA AAAAA ABBAB AAABB ABAAA ABABB ABAAA ABABA AABAA AAABB ABBBA AABBA AAAAA ABBAB AAABB AAAAA ABBBB ABBBB ABABB AABAA AAAAA ABBAB AAABB BAABB BAAAB AABAA AABAA",
    )
    assert res == "HELLOMYNAMEISBEEANDILIKEDOGANDAPPLEANDTREE"

def test_baconian_standard_variant():
    res = decrypt(
        Config().library_default().complete_config(),
        "AABBB AABAA ABABA ABABA ABBAB ABABB BABBA ABBAA AAAAA ABABB AABAA ABAAA BAAAB AAAAB AABAA AABAA AAAAA ABBAA AAABB ABAAA ABABA ABAAA ABAAB AABAA AAABB ABBAB AABBA AAAAA ABBAA AAABB AAAAA ABBBA ABBBA ABABA AABAA AAAAA ABBAA AAABB BAABA BAAAA AABAA AABAA",
    )
    assert res == "HELLOMYNAMEISBEEANDILIKEDOGANDAPPLEANDTREE"

def test_base32():
    res = decrypt(
        Config().library_default().complete_config(),
        "JBSWY3DPEBWXSIDOMFWWKIDJOMQGEZLFEBQW4ZBAJEQGY2LLMUQGI33HEBQW4ZBAMFYHA3DFEBQW4ZBAORZGKZI=",
    )
    assert res == answer_str

def test_base58_bitcoin():
    res = decrypt(
        Config().library_default().complete_config(),
        "6qYhNwsP46Mn4gy6gyANfsMm2icAxGFA6gnFjVm9phYHeby7PZm3vthiXxSU77teQgTFGbHETn",
    )
    assert res == answer_str

def test_base58_ripple():
    res = decrypt(
        Config().library_default().complete_config(),
        "aqY64A1PhaM8hgyagyw4C1Mmp5cwxGEwag8EjVm9F6YHebyfPZmsvt65XxS7ffteQgTEGbHNT8",
    )
    assert res == answer_str

def test_base62():
    res = decrypt(
        Config().library_default().complete_config(),
        "2mQvnz9Yevvb7DRCuyDltsP31vJLToR5pjE9orWkzHMUsht2kbC96PLbZ1sdIocsGHENrzC2n",
    )
    assert res == answer_str

def test_base64():
    res = decrypt(
        Config().library_default().complete_config(),
        "SGVsbG8gbXkgbmFtZSBpcyBiZWUgYW5kIEkgbGlrZSBkb2cgYW5kIGFwcGxlIGFuZCB0cmVl",
    )

    assert res == answer_str

def test_base69():
    res = decrypt(
        Config().library_default().complete_config(),
        "kAZAtABBeB8A-AoB8ADBNAhBLA1AFBgA0AXBfBGATAVAFBgAwAWBHB<ACAkA-AnB0AVBnBNBDARAZBiBQAYAtAhBhABA<ArB4AbAMANBDAFAXBfBQAdAOAmArAUAAA2=",
    )
    assert res == answer_str

def test_base85():
    res = decrypt(
        Config().library_default().complete_config(),
        "87cURD]inB+DtV)AKY].+C\\nn+CT.u+A!\\lBkq9&A8c*'@;]Tu@;p1%AKYE!A0>u7ARt",
    )
    assert res == answer_str

def test_base91():
    res = decrypt(
        Config().library_default().complete_config(),
        ">OwJh>=/fV@$x88j9ZNKB*ge$yV%lE%ZKi,<d,TX2$0t,,cjPD@JY<UCHRWznuWoQPD",
    )
    assert res == answer_str

def test_baudot():
    res = decrypt(
        Config().library_default().complete_config(),
        "10100 00001 10010 10010 11000 00100 11100 10101 00100 01100 00011 11100 00001 00100 00110 00101 00100 11001 00001 00001 00100 00011 01100 01001 00100 00110 00100 10010 00110 01111 00001 00100 01001 11000 11010 00100 00011 01100 01001 00100 00011 10110 10110 10010 00001 00100 00011 01100 01001 00100 10000 01010 00001 00001",
    )
    assert res == answer_str.upper()

def test_binary():
    res = decrypt(
        Config().library_default().complete_config(),
        "01001000 01100101 01101100 01101100 01101111 00100000 01101101 01111001 00100000 01101110 01100001 01101101 01100101 00100000 01101001 01110011 00100000 01100010 01100101 01100101 00100000 01100001 01101110 01100100 00100000 01001001 00100000 01101100 01101001 01101011 01100101 00100000 01100100 01101111 01100111 00100000 01100001 01101110 01100100 00100000 01100001 01110000 01110000 01101100 01100101 00100000 01100001 01101110 01100100 00100000 01110100 01110010 01100101 01100101",
    )

    assert res == answer_str

@pytest.mark.skip(
    "Can't decode base64 + caesar https://github.com/Ciphey/Ciphey/issues/606"
)
def test_binary_base64_caesar():
    res = decrypt(
        Config().library_default().complete_config(),
        "01010110 01011000 01001010 00110101 01100101 01010111 01001001 01100111 01100101 01101101 01110111 01100111 01011001 01010111 00110101 00110110 01100011 01101001 01000010 00110010 01011010 01101001 01000010 01110110 01100011 01101110 01001001 01100111 01100010 01101101 01000110 01111000 01001001 01000110 01011001 01100111 01100101 01011000 01011010 00110100 01100011 01101001 01000010 01111000 01011001 01101110 01010001 01100111 01100010 01101101 01000110 01111000 01001001 01000111 00110101 01101010 01011001 00110011 01101100 01111001 01001001 01000111 00110101 01101000 01100011 01010011 01000010 01101110 01011010 01011000 01001010 01111001 00001010",
    )

    assert res == answer_str

def test_braille():
    res = decrypt(
        Config.library_default().complete_config(),
        "⠓⠑⠇⠇⠕⠀⠍⠽⠀⠝⠁⠍⠑⠀⠊⠎⠀⠃⠑⠑⠀⠁⠝⠙⠀⠊⠀⠇⠊⠅⠑⠀⠙⠕⠛⠀⠁⠝⠙⠀⠁⠏⠏⠇⠑⠀⠁⠝⠙⠀⠞⠗⠑⠑",
    )
    assert res == answer_str.lower()

def test_brainfuck():
    res = decrypt(
        Config().library_default().complete_config(),
        "+[+++++++>+<]>-.-[+>-----<]>++.+++++++..+++.+[+>++<]>.[++>+<]>---.--[+++>-<]>.-[+>++++<]>.[++>+<]>--.-[+++>++<]>-.+[-->---<]>.--------.[+++++>+<]>+.-[+++>--<]>-.++++++++++.---[+>++<]>.[+++>-<]>++.+++..[+++++>+<]>+.[+++>-<]>+.+[-->---<]>+.----------.-[+++>-<]>-.-[+++>+<]>--.-[+>----<]>.++[+++>--<]>.---.++.------.[+++++>+<]>+.+[+>---<]>+.+++++++++++.--------.-[+++>-<]>--.[+++>-<]>+.+[-->---<]>+.----------.-[+++>-<]>-.[+++>-<]>+.-[-->---<]>..----.-------.[+++++>+<]>+.[+++>-<]>+.+[-->---<]>+.----------.-[+++>-<]>-.[++>+<]>++++.--.-------------..",
    )
    assert res == answer_str

def test_brandon():
    res = decrypt(
        Config().library_default().complete_config(),
        "R hvv blf tzgsvi yvuliv nv...sfmtib...gviirurvw... Xofgxsrmt blfi yzyvh gl blfi yivzhg. Vnkvili Vnsbi srh nzixsvw srh ovtrlmh rmgl lfi ozmwh... Ozrw hrvtv gl vevib uligivhh uiln sviv gl gsv Yofv Nlfmgzrmh. Izyrw zmw izevmlfh, sv yrgvh zmw yrgvh zdzb. Nvm lu gsv Mligs, blf hgzmw zg gsv kivxrkrxv. Blfi prmth szev uzrovw blf, hl mld blf gfim gl gsv tlwh! Zmw bvg blf wl mlg kovzw? Blf wl mlg pmvvo gl wfhg blfi svzwh drgs zhs? Rmhgvzw blf dzro,  Dsb szev gsv tlwh ulihzpvm fh?  Dv nfhg ollp rmgl gsv girzoh dv uzrovw olmt ztl! Rm z grnv kzhhvw, lfi dliow rmgvigdrmvw drgs zmlgsvi gsilfts zm fksvzezo hxslozih xzoo gsv Xlmqfmxgrlm lu gsv Hksvivh... Gsv tlwh zooldvw fmslob ulixvh gl hork rmgl lfi wlnzrm. Gsv luuhkirmt lu gszg xzgzxobhn dzh gsv mvuvirlfh ulixv xzoovw nztrx... Bvg dv wrw mlg yzmrhs rg, rmhgvzw hgfwbrmt gsv erov zixzmv uli lfi kldvi zmw dvzogs! Zmw gsv nlmhgvih zg lfi wlli...gsv fmslob ivorxgh lu gsrh Xlmqfmxgrlm? ...gsv gilooh...gsv xlikhv vzgvih...gsv dvivdloevh? Wrw dv izrhv lfi hdliwh ztzrmhg gsvn? Li szev dv ozrw gsrh yfiwvm lm lgsvih? Lm hl-xzoovw drgxsvih? Hgizb xsrowivm gzftsg gsv dzbh lu ulfo hlixvib, gsvri ylwrvh nfgzgvw gsilfts yozhksvnlfh irgfzo. Hvmg gl urtsg nlmhgvih gslfts gsvb xlfow mlg wrhgrmtfrhs tllw uiln vero. Gsv uorxpvi lu sfnzmrgb olmt vcgrmtfrhsvw drgsrm gsvn. Bvh, gsvri mfnyvih szev wdrmwovw gsilfts gsv bvzih. Yfg z uvd hgroo ilzn lfi ozmwh, luuvirmt gsvri yollwb dlip uli xlrm. Gl gsrh wzb gsvb hsznv fh drgs gsvri evib vcrhgvmxv! Gsv Mligs yovvwh, uolttvw yb dzi. Gsv yzggovh ziv gsv tlwh' dsrk, xszhgrhvnvmg uli lfi hrmh! Zmw ovg fh mlg ulitvg gsv gviilih, gsv hxlfitvh uiln yvblmw lfi dliow! Gsv Drow Sfmg irwvh gsv hpb drgs vevib ufoo nllm! Gsv wzip izrwvih zywfxg lfi xsrowivm rmgl ozmwh fmpmldm! Hlnv hzb gsvb svizow z hvxlmw Xlmqfmxgrlm! Xzm dv xszig z xlfihv yzxp rmgl gsv ortsg? Droo dv urmw gsv hgivmtgs gl yzmrhs gsv nztvh uiln lfi prmtwlnh? Fmrgv zilfmw gsv dzings lu gsv Vgvimzo Uriv? Mrts rh gsv Grnv lu gsv Hdliw zmw gsv Zcv! Mlmv droo urtsg gsrh dzi rm lfi hgvzw! Mrts rh gsv Grnv lu Nzwmvhh zmw Wrhwzrm!",
    )
    assert bool(res) is True

def test_caesar():
    res = decrypt(
        Config().library_default().complete_config(),
        "Uryyb zl anzr vf orr naq V yvxr qbt naq nccyr naq gerr",
    )
    assert res == answer_str

def test_decimal():
    res = decrypt(
        Config().library_default().complete_config(),
        "72 101 108 108 111 32 109 121 32 110 97 109 101 32 105 115 32 98 101 101 32 97 110 100 32 73 32 108 105 107 101 32 100 111 103 32 97 110 100 32 97 112 112 108 101 32 97 110 100 32 116 114 101 101",
    )
    assert res == answer_str

def test_dna():
    res = decrypt(
        Config().library_default().complete_config(),
        "GAT AAT GCT ATT TCT ATT AAT ACT GAA CGT GAA TCT ACT ATT AAT GGT",
    )
    assert res == "DNAISINTERESTING"

def test_dtmf():
    res = decrypt(
        Config().library_default().complete_config(),
        "1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1336-941 1209-697 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1209-697 1336-941 1209-697 1336-941 1336-941 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697",
    )
    assert res == answer_str

def test_galactic():
    res = decrypt(
        Config().library_default().complete_config(),
        "⍑ᒷꖎꖎ𝙹 ᒲ|| リᔑᒲᒷ ╎ᓭ ʖᒷᒷ ᔑリ↸ i ꖎ╎ꖌᒷ ↸𝙹⊣ ᔑリ↸ ᔑ!¡!¡ꖎᒷ ᔑリ↸ ℸ ̣ ∷ᒷᒷ",
    )
    assert res == answer_str.lower()

def test_galactic_Xproblem():
    res = decrypt(
        Config().library_default().complete_config(),
        "⍑ᔑꖎ╎⎓ᔑ ̇/,  ̇/||ꖎ𝙹!¡⍑𝙹リᒷ, ᔑ  ̇/ ᔑꖎ𝙹リᒷ ᔑリ↸  ̇/ᒷ∷𝙹 ̇/ ⎓∷𝙹ᒲ 𝙹 ̇/⎓𝙹∷↸",
    )
    assert res == "halifax, xylophone, a x alone and xerox from oxford"

def test_gzip():
    res = decrypt(
        Config().library_default().complete_config(),
        "H4sIAAzul18A/yXJzQmAMBSEwVa+ckwZT7LIw80P6sXuA3ocZpM9aC89msibXSJ6peA8RR3Hx5jTfzyXtAAbQvCyNgAAAA==",
    )
    assert res == answer_str

def test_hexadecimal():
    res = decrypt(
        Config().library_default().complete_config(),
        "48 65 6c 6c 6f 20 6d 79 20 6e 61 6d 65 20 69 73 20 62 65 65 20 61 6e 64 20 49 20 6c 69 6b 65 20 64 6f 67 20 61 6e 64 20 61 70 70 6c 65 20 61 6e 64 20 74 72 65 65",
    )

    assert res == answer_str

def test_json_problem():
    res = decrypt(
        Config().library_default().complete_config(),
        "0110100001100101011011000110110001101111",
    )
    assert res != "0110100001100101011011000110110001101111"

def test_leetspeak():
    res = decrypt(
        Config().library_default().complete_config(),
        "|-|3ll0 my n4m3 1s 833 4nd 1 l1k3 D06 4ND 4ppl3 4nd 7R33",
    )
    assert res.lower() == answer_str.lower()

def test_morse_code():
    res = decrypt(
        Config().library_default().complete_config(),
        ".... . .-.. .-.. ---/-- -.--/-. .- -- ./.. .../-... . ./.- -. -../../.-.. .. -.- ./-.. --- --./.- -. -../.- .--. .--. .-.. ./.- -. -../- .-. . .",
    )
    assert res == answer_str.upper()

def test_multi_tap():
    res = decrypt(
        Config().library_default().complete_config(),
        "44 33 555 555 666 0 6 999 0 66 2 6 33 0 444 7777 0 22 33 33 0 2 66 3 0 444 0 555 444 55 33 0 3 666 4 0 2 66 3 0 2 7 7 555 33 0 2 66 3 0 8 777 33 33",
    )
    assert res == answer_str.upper()

def test_new_line_at_start_returns():
    # Language Checker should return True by stripping new line
    # but the new line should be returned to the user as new lines are important
    res = decrypt(Config().library_default().complete_config(), "\npass\n")

    assert res == "\npass\n"

def test_new_line_strip_and_return():
    # Language Checker should return True by stripping new line
    # but the new line should be returned to the user as new lines are important
    res = decrypt(Config().library_default().complete_config(), "pass\n")

    assert res == "pass\n"

def test_octal():
    res = decrypt(
        Config().library_default().complete_config(),
        "110 145 154 154 157 40 155 171 40 156 141 155 145 40 151 163 40 142 145 145 40 141 156 144 40 111 40 154 151 153 145 40 144 157 147 40 141 156 144 40 141 160 160 154 145 40 141 156 144 40 164 162 145 145",
    )
    assert res == answer_str

def test_plaintext():
    res = decrypt(Config().library_default().complete_config(), answer_str)
    assert res == answer_str

def test_quadgrams_messed_up_spacing():
    res = decrypt(
        Config().library_default().complete_config(),
        "H ello m y na m e is b ee an d I l ik e do g a n d ap pl e a nd tr e e",
    )
    assert (
        res == "H ello m y na m e is b ee an d I l ik e do g a n d ap pl e a nd tr e e"
    )

def test_quadgrams_no_spaces():
    res = decrypt(
        Config().library_default().complete_config(),
        "HellomynameisbeeandIlikedogandappleandtree",
    )
    assert res == "HellomynameisbeeandIlikedogandappleandtree"

def test_quadgrams_space_between_every_letter():
    res = decrypt(
        Config().library_default().complete_config(),
        "H e l l o m y n a m e i s b e e a n d I l i k e d o g a n d a p p l e a n d t r e e",
    )
    assert (
        res
        == "H e l l o m y n a m e i s b e e a n d I l i k e d o g a n d a p p l e a n d t r e e"
    )

def test_reversed_text():
    res = decrypt(
        Config().library_default().complete_config(),
        "eert dna elppa dna god ekil I dna eeb si eman ym olleH",
    )
    assert res == answer_str

def test_rot47():
    res = decrypt(
        Config().library_default().complete_config(),
        "$A9:?I @7 3=24< BF2CEK[ ;F586 >J G@H",
    )
    assert res == "Sphinx of black quartz, judge my vow"

def test_soundex():
    res = decrypt(
        Config().library_default().complete_config(),
        "H236 I200 I500 T000 P230",
    )
    assert res.lower() == "history is in the past"

def test_tap_code():
    res = decrypt(
        Config().library_default().complete_config(),
        "4,4 1,5 4,3 4,4  3,4 3,3 1,5  4,4 5,2 3,4  4,4 2,3 4,2 1,5 1,5",
    )
    assert res == "test one two three".upper()

def test_url():
    res = decrypt(
        Config().library_default().complete_config(),
        "https%3A%2F%2Fwww%2Egoogle%2Ecom%2Fsearch%3Fq%3Dciphey",
    )
    assert res == "https://www.google.com/search?q=ciphey"

def test_uuencode():
    res = decrypt(
        Config().library_default().complete_config(),
        'begin 644 /dev/stdout\nM2&5L;&\\@;7D@;F%M92!I<R!B964@86YD($D@;&EK92!D;V<@86YD(&%P<&QE\n)(&%N9"!T<F5E\n`\nend\n',
    )
    assert res == answer_str
    res = decrypt(
        Config().library_default().complete_config(),
        'M2&5L;&\\@;7D@;F%M92!I<R!B964@86YD($D@;&EK92!D;V<@86YD(&%P<&QE\n)(&%N9"!T<F5E\n',
    )
    assert res == answer_str

def test_vigenere():
    res = decrypt(
        Config().library_default().complete_config(),
        "Rijvs ki rywi gc fco eln M jsoc nse krb ktnvi yxh rbic",
    )

    assert res == answer_str

def test_xandy():
    res = decrypt(
        Config().library_default().complete_config(),
        "xDxxDxxx xDDxxDxD xDDxDDxx xDDxDDxx xDDxDDDD xxDxxxxx xDDxDDxD xDDDDxxD xxDxxxxx xDDxDDDx xDDxxxxD xDDxDDxD xDDxxDxD xxDxxxxx xDDxDxxD xDDDxxDD xxDxxxxx xDDxxxDx xDDxxDxD xDDxxDxD xxDxxxxx xDDxxxxD xDDxDDDx xDDxxDxx xxDxxxxx xDxxDxxD xxDxxxxx xDDxDDxx xDDxDxxD xDDxDxDD xDDxxDxD xxDxxxxx xDDxxDxx xDDxDDDD xDDxxDDD xxDxxxxx xDDxxxxD xDDxDDDx xDDxxDxx xxDxxxxx xDDxxxxD xDDDxxxx xDDDxxxx xDDxDDxx xDDxxDxD xxDxxxxx xDDxxxxD xDDxDDDx xDDxxDxx xxDxxxxx xDDDxDxx xDDDxxDx xDDxxDxD xDDxxDxD",
    )
    assert res == answer_str


Question: What is the expected decrypted plaintext used in most of the tests?

Answer: Most of the tests expect the decrypted result to match the string stored in the answer_str variable, which is set to "Hello my name is bee and I like dog and apple and tree". For example, the test_base64 function checks that decrypting the base64 string "SGVsbG8gbXkgbmFtZSBpcyBiZWUgYW5kIEkgbGlrZSBkb2cgYW5kIGFwcGxlIGFuZCB0cmVl" results in answer_str.

import pytest

from ciphey import decrypt
from ciphey.iface import Config

answer_str = "Hello my name is bee and I like dog and apple and tree"

def test_a1z26():
    res = decrypt(
        Config().library_default().complete_config(),
        "8 5 12 12 15 13 25 14 1 13 5 9 19 2 5 5 1 14 4 9 12 9 11 5 4 15 7 1 14 4 1 16 16 12 5 1 14 4 20 18 5 5",
    )
    assert res == "hellomynameisbeeandilikedogandappleandtree"

def test_affine():
    res = decrypt(
        Config().library_default().complete_config(),
        "Ihsst bf kxbh rd ghh xky R srjh ytz xky xccsh xky muhh",
    )
    assert res == answer_str

def test_ascii_shift():
    res = decrypt(
        Config().library_default().complete_config(),
        '"?FFIzGSzH;G?zCMz<??z;H>z#zFCE?z>IAz;H>z;JJF?z;H>zNL??',
    )
    assert res == answer_str

def test_atbash():
    res = decrypt(
        Config().library_default().complete_config(),
        "Svool nb mznv rh yvv zmw R orpv wlt zmw zkkov zmw givv",
    )
    assert res == answer_str

def test_baconian_complete_variant():
    res = decrypt(
        Config().library_default().complete_config(),
        "AABBB AABAA ABABB ABABB ABBBA ABBAA BBAAA ABBAB AAAAA ABBAA AABAA ABAAA BAABA AAAAB AABAA AABAA AAAAA ABBAB AAABB ABAAA ABABB ABAAA ABABA AABAA AAABB ABBBA AABBA AAAAA ABBAB AAABB AAAAA ABBBB ABBBB ABABB AABAA AAAAA ABBAB AAABB BAABB BAAAB AABAA AABAA",
    )
    assert res == "HELLOMYNAMEISBEEANDILIKEDOGANDAPPLEANDTREE"

def test_baconian_standard_variant():
    res = decrypt(
        Config().library_default().complete_config(),
        "AABBB AABAA ABABA ABABA ABBAB ABABB BABBA ABBAA AAAAA ABABB AABAA ABAAA BAAAB AAAAB AABAA AABAA AAAAA ABBAA AAABB ABAAA ABABA ABAAA ABAAB AABAA AAABB ABBAB AABBA AAAAA ABBAA AAABB AAAAA ABBBA ABBBA ABABA AABAA AAAAA ABBAA AAABB BAABA BAAAA AABAA AABAA",
    )
    assert res == "HELLOMYNAMEISBEEANDILIKEDOGANDAPPLEANDTREE"

def test_base32():
    res = decrypt(
        Config().library_default().complete_config(),
        "JBSWY3DPEBWXSIDOMFWWKIDJOMQGEZLFEBQW4ZBAJEQGY2LLMUQGI33HEBQW4ZBAMFYHA3DFEBQW4ZBAORZGKZI=",
    )
    assert res == answer_str

def test_base58_bitcoin():
    res = decrypt(
        Config().library_default().complete_config(),
        "6qYhNwsP46Mn4gy6gyANfsMm2icAxGFA6gnFjVm9phYHeby7PZm3vthiXxSU77teQgTFGbHETn",
    )
    assert res == answer_str

def test_base58_ripple():
    res = decrypt(
        Config().library_default().complete_config(),
        "aqY64A1PhaM8hgyagyw4C1Mmp5cwxGEwag8EjVm9F6YHebyfPZmsvt65XxS7ffteQgTEGbHNT8",
    )
    assert res == answer_str

def test_base62():
    res = decrypt(
        Config().library_default().complete_config(),
        "2mQvnz9Yevvb7DRCuyDltsP31vJLToR5pjE9orWkzHMUsht2kbC96PLbZ1sdIocsGHENrzC2n",
    )
    assert res == answer_str

def test_base64():
    res = decrypt(
        Config().library_default().complete_config(),
        "SGVsbG8gbXkgbmFtZSBpcyBiZWUgYW5kIEkgbGlrZSBkb2cgYW5kIGFwcGxlIGFuZCB0cmVl",
    )

    assert res == answer_str

def test_base69():
    res = decrypt(
        Config().library_default().complete_config(),
        "kAZAtABBeB8A-AoB8ADBNAhBLA1AFBgA0AXBfBGATAVAFBgAwAWBHB<ACAkA-AnB0AVBnBNBDARAZBiBQAYAtAhBhABA<ArB4AbAMANBDAFAXBfBQAdAOAmArAUAAA2=",
    )
    assert res == answer_str

def test_base85():
    res = decrypt(
        Config().library_default().complete_config(),
        "87cURD]inB+DtV)AKY].+C\\nn+CT.u+A!\\lBkq9&A8c*'@;]Tu@;p1%AKYE!A0>u7ARt",
    )
    assert res == answer_str

def test_base91():
    res = decrypt(
        Config().library_default().complete_config(),
        ">OwJh>=/fV@$x88j9ZNKB*ge$yV%lE%ZKi,<d,TX2$0t,,cjPD@JY<UCHRWznuWoQPD",
    )
    assert res == answer_str

def test_baudot():
    res = decrypt(
        Config().library_default().complete_config(),
        "10100 00001 10010 10010 11000 00100 11100 10101 00100 01100 00011 11100 00001 00100 00110 00101 00100 11001 00001 00001 00100 00011 01100 01001 00100 00110 00100 10010 00110 01111 00001 00100 01001 11000 11010 00100 00011 01100 01001 00100 00011 10110 10110 10010 00001 00100 00011 01100 01001 00100 10000 01010 00001 00001",
    )
    assert res == answer_str.upper()

def test_binary():
    res = decrypt(
        Config().library_default().complete_config(),
        "01001000 01100101 01101100 01101100 01101111 00100000 01101101 01111001 00100000 01101110 01100001 01101101 01100101 00100000 01101001 01110011 00100000 01100010 01100101 01100101 00100000 01100001 01101110 01100100 00100000 01001001 00100000 01101100 01101001 01101011 01100101 00100000 01100100 01101111 01100111 00100000 01100001 01101110 01100100 00100000 01100001 01110000 01110000 01101100 01100101 00100000 01100001 01101110 01100100 00100000 01110100 01110010 01100101 01100101",
    )

    assert res == answer_str

@pytest.mark.skip(
    "Can't decode base64 + caesar https://github.com/Ciphey/Ciphey/issues/606"
)
def test_binary_base64_caesar():
    res = decrypt(
        Config().library_default().complete_config(),
        "01010110 01011000 01001010 00110101 01100101 01010111 01001001 01100111 01100101 01101101 01110111 01100111 01011001 01010111 00110101 00110110 01100011 01101001 01000010 00110010 01011010 01101001 01000010 01110110 01100011 01101110 01001001 01100111 01100010 01101101 01000110 01111000 01001001 01000110 01011001 01100111 01100101 01011000 01011010 00110100 01100011 01101001 01000010 01111000 01011001 01101110 01010001 01100111 01100010 01101101 01000110 01111000 01001001 01000111 00110101 01101010 01011001 00110011 01101100 01111001 01001001 01000111 00110101 01101000 01100011 01010011 01000010 01101110 01011010 01011000 01001010 01111001 00001010",
    )

    assert res == answer_str

def test_braille():
    res = decrypt(
        Config.library_default().complete_config(),
        "⠓⠑⠇⠇⠕⠀⠍⠽⠀⠝⠁⠍⠑⠀⠊⠎⠀⠃⠑⠑⠀⠁⠝⠙⠀⠊⠀⠇⠊⠅⠑⠀⠙⠕⠛⠀⠁⠝⠙⠀⠁⠏⠏⠇⠑⠀⠁⠝⠙⠀⠞⠗⠑⠑",
    )
    assert res == answer_str.lower()

def test_brainfuck():
    res = decrypt(
        Config().library_default().complete_config(),
        "+[+++++++>+<]>-.-[+>-----<]>++.+++++++..+++.+[+>++<]>.[++>+<]>---.--[+++>-<]>.-[+>++++<]>.[++>+<]>--.-[+++>++<]>-.+[-->---<]>.--------.[+++++>+<]>+.-[+++>--<]>-.++++++++++.---[+>++<]>.[+++>-<]>++.+++..[+++++>+<]>+.[+++>-<]>+.+[-->---<]>+.----------.-[+++>-<]>-.-[+++>+<]>--.-[+>----<]>.++[+++>--<]>.---.++.------.[+++++>+<]>+.+[+>---<]>+.+++++++++++.--------.-[+++>-<]>--.[+++>-<]>+.+[-->---<]>+.----------.-[+++>-<]>-.[+++>-<]>+.-[-->---<]>..----.-------.[+++++>+<]>+.[+++>-<]>+.+[-->---<]>+.----------.-[+++>-<]>-.[++>+<]>++++.--.-------------..",
    )
    assert res == answer_str

def test_brandon():
    res = decrypt(
        Config().library_default().complete_config(),
        "R hvv blf tzgsvi yvuliv nv...sfmtib...gviirurvw... Xofgxsrmt blfi yzyvh gl blfi yivzhg. Vnkvili Vnsbi srh nzixsvw srh ovtrlmh rmgl lfi ozmwh... Ozrw hrvtv gl vevib uligivhh uiln sviv gl gsv Yofv Nlfmgzrmh. Izyrw zmw izevmlfh, sv yrgvh zmw yrgvh zdzb. Nvm lu gsv Mligs, blf hgzmw zg gsv kivxrkrxv. Blfi prmth szev uzrovw blf, hl mld blf gfim gl gsv tlwh! Zmw bvg blf wl mlg kovzw? Blf wl mlg pmvvo gl wfhg blfi svzwh drgs zhs? Rmhgvzw blf dzro,  Dsb szev gsv tlwh ulihzpvm fh?  Dv nfhg ollp rmgl gsv girzoh dv uzrovw olmt ztl! Rm z grnv kzhhvw, lfi dliow rmgvigdrmvw drgs zmlgsvi gsilfts zm fksvzezo hxslozih xzoo gsv Xlmqfmxgrlm lu gsv Hksvivh... Gsv tlwh zooldvw fmslob ulixvh gl hork rmgl lfi wlnzrm. Gsv luuhkirmt lu gszg xzgzxobhn dzh gsv mvuvirlfh ulixv xzoovw nztrx... Bvg dv wrw mlg yzmrhs rg, rmhgvzw hgfwbrmt gsv erov zixzmv uli lfi kldvi zmw dvzogs! Zmw gsv nlmhgvih zg lfi wlli...gsv fmslob ivorxgh lu gsrh Xlmqfmxgrlm? ...gsv gilooh...gsv xlikhv vzgvih...gsv dvivdloevh? Wrw dv izrhv lfi hdliwh ztzrmhg gsvn? Li szev dv ozrw gsrh yfiwvm lm lgsvih? Lm hl-xzoovw drgxsvih? Hgizb xsrowivm gzftsg gsv dzbh lu ulfo hlixvib, gsvri ylwrvh nfgzgvw gsilfts yozhksvnlfh irgfzo. Hvmg gl urtsg nlmhgvih gslfts gsvb xlfow mlg wrhgrmtfrhs tllw uiln vero. Gsv uorxpvi lu sfnzmrgb olmt vcgrmtfrhsvw drgsrm gsvn. Bvh, gsvri mfnyvih szev wdrmwovw gsilfts gsv bvzih. Yfg z uvd hgroo ilzn lfi ozmwh, luuvirmt gsvri yollwb dlip uli xlrm. Gl gsrh wzb gsvb hsznv fh drgs gsvri evib vcrhgvmxv! Gsv Mligs yovvwh, uolttvw yb dzi. Gsv yzggovh ziv gsv tlwh' dsrk, xszhgrhvnvmg uli lfi hrmh! Zmw ovg fh mlg ulitvg gsv gviilih, gsv hxlfitvh uiln yvblmw lfi dliow! Gsv Drow Sfmg irwvh gsv hpb drgs vevib ufoo nllm! Gsv wzip izrwvih zywfxg lfi xsrowivm rmgl ozmwh fmpmldm! Hlnv hzb gsvb svizow z hvxlmw Xlmqfmxgrlm! Xzm dv xszig z xlfihv yzxp rmgl gsv ortsg? Droo dv urmw gsv hgivmtgs gl yzmrhs gsv nztvh uiln lfi prmtwlnh? Fmrgv zilfmw gsv dzings lu gsv Vgvimzo Uriv? Mrts rh gsv Grnv lu gsv Hdliw zmw gsv Zcv! Mlmv droo urtsg gsrh dzi rm lfi hgvzw! Mrts rh gsv Grnv lu Nzwmvhh zmw Wrhwzrm!",
    )
    assert bool(res) is True

def test_caesar():
    res = decrypt(
        Config().library_default().complete_config(),
        "Uryyb zl anzr vf orr naq V yvxr qbt naq nccyr naq gerr",
    )
    assert res == answer_str

def test_decimal():
    res = decrypt(
        Config().library_default().complete_config(),
        "72 101 108 108 111 32 109 121 32 110 97 109 101 32 105 115 32 98 101 101 32 97 110 100 32 73 32 108 105 107 101 32 100 111 103 32 97 110 100 32 97 112 112 108 101 32 97 110 100 32 116 114 101 101",
    )
    assert res == answer_str

def test_dna():
    res = decrypt(
        Config().library_default().complete_config(),
        "GAT AAT GCT ATT TCT ATT AAT ACT GAA CGT GAA TCT ACT ATT AAT GGT",
    )
    assert res == "DNAISINTERESTING"

def test_dtmf():
    res = decrypt(
        Config().library_default().complete_config(),
        "1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1336-941 1209-697 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1209-697 1336-941 1336-941 1336-941 1336-941 1336-941 1336-941 1209-697 1209-697 1209-697 1336-941 1209-697 1336-941 1336-941 1336-941 1209-697 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697 1336-941 1209-697 1209-697 1336-941 1336-941 1209-697 1336-941 1209-697",
    )
    assert res == answer_str

def test_galactic():
    res = decrypt(
        Config().library_default().complete_config(),
        "⍑ᒷꖎꖎ𝙹 ᒲ|| リᔑᒲᒷ ╎ᓭ ʖᒷᒷ ᔑリ↸ i ꖎ╎ꖌᒷ ↸𝙹⊣ ᔑリ↸ ᔑ!¡!¡ꖎᒷ ᔑリ↸ ℸ ̣ ∷ᒷᒷ",
    )
    assert res == answer_str.lower()

def test_galactic_Xproblem():
    res = decrypt(
        Config().library_default().complete_config(),
        "⍑ᔑꖎ╎⎓ᔑ ̇/,  ̇/||ꖎ𝙹!¡⍑𝙹リᒷ, ᔑ  ̇/ ᔑꖎ𝙹リᒷ ᔑリ↸  ̇/ᒷ∷𝙹 ̇/ ⎓∷𝙹ᒲ 𝙹 ̇/⎓𝙹∷↸",
    )
    assert res == "halifax, xylophone, a x alone and xerox from oxford"

def test_gzip():
    res = decrypt(
        Config().library_default().complete_config(),
        "H4sIAAzul18A/yXJzQmAMBSEwVa+ckwZT7LIw80P6sXuA3ocZpM9aC89msibXSJ6peA8RR3Hx5jTfzyXtAAbQvCyNgAAAA==",
    )
    assert res == answer_str

def test_hexadecimal():
    res = decrypt(
        Config().library_default().complete_config(),
        "48 65 6c 6c 6f 20 6d 79 20 6e 61 6d 65 20 69 73 20 62 65 65 20 61 6e 64 20 49 20 6c 69 6b 65 20 64 6f 67 20 61 6e 64 20 61 70 70 6c 65 20 61 6e 64 20 74 72 65 65",
    )

    assert res == answer_str

def test_json_problem():
    res = decrypt(
        Config().library_default().complete_config(),
        "0110100001100101011011000110110001101111",
    )
    assert res != "0110100001100101011011000110110001101111"

def test_leetspeak():
    res = decrypt(
        Config().library_default().complete_config(),
        "|-|3ll0 my n4m3 1s 833 4nd 1 l1k3 D06 4ND 4ppl3 4nd 7R33",
    )
    assert res.lower() == answer_str.lower()

def test_morse_code():
    res = decrypt(
        Config().library_default().complete_config(),
        ".... . .-.. .-.. ---/-- -.--/-. .- -- ./.. .../-... . ./.- -. -../../.-.. .. -.- ./-.. --- --./.- -. -../.- .--. .--. .-.. ./.- -. -../- .-. . .",
    )
    assert res == answer_str.upper()

def test_multi_tap():
    res = decrypt(
        Config().library_default().complete_config(),
        "44 33 555 555 666 0 6 999 0 66 2 6 33 0 444 7777 0 22 33 33 0 2 66 3 0 444 0 555 444 55 33 0 3 666 4 0 2 66 3 0 2 7 7 555 33 0 2 66 3 0 8 777 33 33",
    )
    assert res == answer_str.upper()

def test_new_line_at_start_returns():
    # Language Checker should return True by stripping new line
    # but the new line should be returned to the user as new lines are important
    res = decrypt(Config().library_default().complete_config(), "\npass\n")

    assert res == "\npass\n"

def test_new_line_strip_and_return():
    # Language Checker should return True by stripping new line
    # but the new line should be returned to the user as new lines are important
    res = decrypt(Config().library_default().complete_config(), "pass\n")

    assert res == "pass\n"

def test_octal():
    res = decrypt(
        Config().library_default().complete_config(),
        "110 145 154 154 157 40 155 171 40 156 141 155 145 40 151 163 40 142 145 145 40 141 156 144 40 111 40 154 151 153 145 40 144 157 147 40 141 156 144 40 141 160 160 154 145 40 141 156 144 40 164 162 145 145",
    )
    assert res == answer_str

def test_plaintext():
    res = decrypt(Config().library_default().complete_config(), answer_str)
    assert res == answer_str

def test_quadgrams_messed_up_spacing():
    res = decrypt(
        Config().library_default().complete_config(),
        "H ello m y na m e is b ee an d I l ik e do g a n d ap pl e a nd tr e e",
    )
    assert (
        res == "H ello m y na m e is b ee an d I l ik e do g a n d ap pl e a nd tr e e"
    )

def test_quadgrams_no_spaces():
    res = decrypt(
        Config().library_default().complete_config(),
        "HellomynameisbeeandIlikedogandappleandtree",
    )
    assert res == "HellomynameisbeeandIlikedogandappleandtree"

def test_quadgrams_space_between_every_letter():
    res = decrypt(
        Config().library_default().complete_config(),
        "H e l l o m y n a m e i s b e e a n d I l i k e d o g a n d a p p l e a n d t r e e",
    )
    assert (
        res
        == "H e l l o m y n a m e i s b e e a n d I l i k e d o g a n d a p p l e a n d t r e e"
    )

def test_reversed_text():
    res = decrypt(
        Config().library_default().complete_config(),
        "eert dna elppa dna god ekil I dna eeb si eman ym olleH",
    )
    assert res == answer_str

def test_rot47():
    res = decrypt(
        Config().library_default().complete_config(),
        "$A9:?I @7 3=24< BF2CEK[ ;F586 >J G@H",
    )
    assert res == "Sphinx of black quartz, judge my vow"

def test_soundex():
    res = decrypt(
        Config().library_default().complete_config(),
        "H236 I200 I500 T000 P230",
    )
    assert res.lower() == "history is in the past"

def test_tap_code():
    res = decrypt(
        Config().library_default().complete_config(),
        "4,4 1,5 4,3 4,4  3,4 3,3 1,5  4,4 5,2 3,4  4,4 2,3 4,2 1,5 1,5",
    )
    assert res == "test one two three".upper()

def test_url():
    res = decrypt(
        Config().library_default().complete_config(),
        "https%3A%2F%2Fwww%2Egoogle%2Ecom%2Fsearch%3Fq%3Dciphey",
    )
    assert res == "https://www.google.com/search?q=ciphey"

def test_uuencode():
    res = decrypt(
        Config().library_default().complete_config(),
        'begin 644 /dev/stdout\nM2&5L;&\\@;7D@;F%M92!I<R!B964@86YD($D@;&EK92!D;V<@86YD(&%P<&QE\n)(&%N9"!T<F5E\n`\nend\n',
    )
    assert res == answer_str
    res = decrypt(
        Config().library_default().complete_config(),
        'M2&5L;&\\@;7D@;F%M92!I<R!B964@86YD($D@;&EK92!D;V<@86YD(&%P<&QE\n)(&%N9"!T<F5E\n',
    )
    assert res == answer_str

def test_vigenere():
    res = decrypt(
        Config().library_default().complete_config(),
        "Rijvs ki rywi gc fco eln M jsoc nse krb ktnvi yxh rbic",
    )

    assert res == answer_str

def test_xandy():
    res = decrypt(
        Config().library_default().complete_config(),
        "xDxxDxxx xDDxxDxD xDDxDDxx xDDxDDxx xDDxDDDD xxDxxxxx xDDxDDxD xDDDDxxD xxDxxxxx xDDxDDDx xDDxxxxD xDDxDDxD xDDxxDxD xxDxxxxx xDDxDxxD xDDDxxDD xxDxxxxx xDDxxxDx xDDxxDxD xDDxxDxD xxDxxxxx xDDxxxxD xDDxDDDx xDDxxDxx xxDxxxxx xDxxDxxD xxDxxxxx xDDxDDxx xDDxDxxD xDDxDxDD xDDxxDxD xxDxxxxx xDDxxDxx xDDxDDDD xDDxxDDD xxDxxxxx xDDxxxxD xDDxDDDx xDDxxDxx xxDxxxxx xDDxxxxD xDDDxxxx xDDDxxxx xDDxDDxx xDDxxDxD xxDxxxxx xDDxxxxD xDDxDDDx xDDxxDxx xxDxxxxx xDDDxDxx xDDDxxDx xDDxxDxD xDDxxDxD",
    )
    assert res == answer_str


Question: What does the MakeBools function return?

Answer:
The MakeBools function returns a vector of uint8_t values representing boolean values. It returns the sequence 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, as seen in the following code:
std::vector<uint8_t> MakeBools() {
    return std::vector<uint8_t> {1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0};
}

#include "value_generators.h"

#include <algorithm>
#include <type_traits>
#include <math.h>

namespace {
using namespace clickhouse;
}

std::vector<uint32_t> MakeNumbers() {
    return std::vector<uint32_t> {1, 2, 3, 7, 11, 13, 17, 19, 23, 29, 31};
}

std::vector<uint8_t> MakeBools() {
    return std::vector<uint8_t> {1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0};
}

std::vector<std::string> MakeFixedStrings(size_t string_size) {
    std::vector<std::string> result = MakeStrings();

    std::for_each(result.begin(), result.end(), [string_size](auto& value) {
        value.resize(string_size, '\0');
    });

    return result;
}

std::vector<std::string> MakeStrings() {
    return {
        "a", "ab", "abc", "abcd",
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
        "long string to test how those are handled. Here goes more text. "
    };
}

std::vector<UUID> MakeUUIDs() {
    return {
        UUID(0llu, 0llu),
        UUID(0xbb6a8c699ab2414cllu, 0x86697b7fd27f0825llu),
        UUID(0x84b9f24bc26b49c6llu, 0xa03b4ab723341951llu),
        UUID(0x3507213c178649f9llu, 0x9faf035d662f60aellu)
    };
}

std::vector<Int64> MakeDateTime64s(size_t scale, size_t values_size) {
    const auto seconds_multiplier = static_cast<size_t>(std::pow(10, scale));
    const auto year = 86400ull * 365 * seconds_multiplier; // ~approx, but this doesn't matter here.

    // Approximatelly +/- 200 years around epoch (and value of epoch itself)
    // with non zero seconds and sub-seconds.
    // Please note there are values outside of DateTime (32-bit) range that might
    // not have correct string representation in CH yet,
    // but still are supported as Int64 values.
    return GenerateVector(values_size,
        [seconds_multiplier, year] (size_t i )-> Int64 {
            return (i - 100) * year * 2 + (i * 10) * seconds_multiplier + i;
        });
}

std::vector<int32_t> MakeDates32() {
    // in CH Date32 internally a UInt32 and stores a day number
    // ColumnDate expects values to be seconds, which is then
    // converted to day number internally, hence the `* 86400`.
    // 114634 * 86400 is 2282-11-10, last integer that fits into DateTime32 range
    // (max is 2283-11-11)
    std::vector<int32_t> result = MakeDates<int32_t>();

    // add corresponding negative values, since pre-epoch date are supported too.
    const auto size = result.size();
    for (size_t i = 0; i < size; ++i) {
        result.push_back(result[i] * -1);
    }

    return result;
}

std::vector<clickhouse::Int64> MakeDateTimes() {
    // in CH DateTime internally a UInt32
    return {
        0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536,
        131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864,
        134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296 - 1
    };
}

std::vector<clickhouse::Int128> MakeInt128s() {
    return {
        absl::MakeInt128(0xffffffffffffffffll, 0xffffffffffffffffll), // -1
        absl::MakeInt128(0, 0xffffffffffffffffll),  // 2^64
        absl::MakeInt128(0xffffffffffffffffll, 0),
        absl::MakeInt128(0x8000000000000000ll, 0),
        Int128(0)
    };
}

std::vector<clickhouse::Int128> MakeDecimals(size_t /*precision*/, size_t scale) {
    const auto scale_multiplier = static_cast<size_t>(std::pow(10, scale));
    const long long int rhs_value = 12345678910;

    const std::vector<long long int> vals {0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 - 1};

    std::vector<clickhouse::Int128> result;
    result.reserve(vals.size());

    std::transform(vals.begin(), vals.end(), std::back_inserter(result), [scale_multiplier, rhs_value](const auto& value) {
        return value * scale_multiplier + rhs_value % scale_multiplier;
    });

    return result;
}

std::string FooBarGenerator(size_t i) {
    std::string result;
    if (i % 3 == 0)
        result += "Foo";
    if (i % 5 == 0)
        result += "Bar";
    if (result.empty())
        result = std::to_string(i);

    return result;
}

std::vector<in_addr> MakeIPv4s() {
    return {
        MakeIPv4(0x12345678), // 255.255.255.255
        MakeIPv4(0x0100007f), // 127.0.0.1
        MakeIPv4(3585395774),
        MakeIPv4(0),
        MakeIPv4(0x12345678),
    };
}

std::vector<in6_addr> MakeIPv6s() {
    return {
        MakeIPv6(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), // 1:203:405:607:809:a0b:c0d:e0f
        MakeIPv6(0, 0, 0, 0, 0, 1),                                     // ::1
        MakeIPv6(0, 0, 0, 0, 0, 0),                                     // ::
        MakeIPv6(0xff, 0xff, 204, 152, 189, 116),                       // ::ffff:204.152.189.116
    };
}


Question: How does the MakeFixedStrings function work?

Answer:
The MakeFixedStrings function takes a size parameter string_size and returns a vector of strings. It first calls the MakeStrings function to get a vector of strings. Then, it resizes each string in the vector to the specified string_size by appending null characters ('\0') to the end of each string using std::for_each and a lambda function. This ensures that all strings in the returned vector have a fixed length of string_size. Here's the relevant code:
std::vector<std::string> MakeFixedStrings(size_t string_size) {
    std::vector<std::string> result = MakeStrings();

    std::for_each(result.begin(), result.end(), [string_size](auto& value) {
        value.resize(string_size, '\0');
    });

    return result;
}


Question: What is the purpose of the long string in the MakeStrings function?

Answer:
The MakeStrings function returns a vector of strings. One of the strings in the returned vector is a long string that is repeated multiple times. The purpose of this long string is to test how the code handles long strings. The comment in the code states:
"long string to test how those are handled. Here goes more text. "
This long string is repeated multiple times to create a sufficiently long string for testing purposes.


Question: What UUID values are returned by the MakeUUIDs function?

Answer:
The MakeUUIDs function returns a vector of UUID values. It returns the following UUIDs:
- UUID(0llu, 0llu)
- UUID(0xbb6a8c699ab2414cllu, 0x86697b7fd27f0825llu)
- UUID(0x84b9f24bc26b49c6llu, 0xa03b4ab723341951llu)
- UUID(0x3507213c178649f9llu, 0x9faf035d662f60aellu)
These UUIDs are hardcoded in the function.


Question: How can I append a column to a ColumnTuple?

Answer: You can append a column to a ColumnTuple using the Append() function. It takes a ColumnRef as an argument and appends the content of the given column to the end of the current ColumnTuple. This is evident from the comment "Appends content of given column to the end of current one."

#pragma once

#include "column.h"
#include "utils.h"

#include <vector>

namespace clickhouse {

/**
 * Represents column of Tuple([T]).
 */
class ColumnTuple : public Column {
public:
    ColumnTuple(const std::vector<ColumnRef>& columns);

    /// Returns count of columns in the tuple.
    size_t TupleSize() const;

    inline ColumnRef operator [] (size_t n) const {
        return columns_[n];
    }

    inline ColumnRef At(size_t n) const {
        return columns_[n];
    }

public:
    /// Increase the capacity of the column for large block insertion.
    void Reserve(size_t new_cap) override;

    /// Appends content of given column to the end of current one.
    void Append(ColumnRef column) override;

    /// Loads column prefix from input stream.
    bool LoadPrefix(InputStream* input, size_t rows) override;

    /// Loads column data from input stream.
    bool LoadBody(InputStream* input, size_t rows) override;

    /// Saves column prefix to output stream.
    void SavePrefix(OutputStream* output) override;

    /// Saves column data to output stream.
    void SaveBody(OutputStream* output) override;

    /// Clear column data .
    void Clear() override;

    /// Returns count of rows in the column.
    size_t Size() const override;

    /// Makes slice of the current column.
    ColumnRef Slice(size_t, size_t) const override;
    ColumnRef CloneEmpty() const override;
    void Swap(Column& other) override;

private:
    std::vector<ColumnRef> columns_;
};

template <typename... Columns>
class ColumnTupleT : public ColumnTuple {
public:
    using TupleOfColumns = std::tuple<std::shared_ptr<Columns>...>;

    using ValueType = std::tuple<std::decay_t<decltype(std::declval<Columns>().At(0))>...>;

    ColumnTupleT(std::tuple<std::shared_ptr<Columns>...> columns)
        : ColumnTuple(TupleToVector(columns)), typed_columns_(std::move(columns)) {}

    ColumnTupleT(std::vector<ColumnRef> columns)
        : ColumnTuple(columns), typed_columns_(VectorToTuple(std::move(columns))) {}

    ColumnTupleT(const std::initializer_list<ColumnRef> columns)
        : ColumnTuple(columns), typed_columns_(VectorToTuple(std::move(columns))) {}

    inline ValueType At(size_t index) const { return GetTupleOfValues(index); }

    inline ValueType operator[](size_t index) const { return GetTupleOfValues(index); }

    using ColumnTuple::Append;

    template <typename... T>
    inline void Append(std::tuple<T...> value) {
        AppendTuple(std::move(value));
    }

    /** Create a ColumnTupleT from a ColumnTuple, without copying data and offsets, but by
     * 'stealing' those from `col`.
     *
     *  Ownership of column internals is transferred to returned object, original (argument) object
     *  MUST NOT BE USED IN ANY WAY, it is only safe to dispose it.
     *
     *  Throws an exception if `col` is of wrong type, it is safe to use original col in this case.
     *  This is a static method to make such conversion verbose.
     */
    static auto Wrap(ColumnTuple&& col) {
        if (col.TupleSize() != std::tuple_size_v<TupleOfColumns>) {
            throw ValidationError("Can't wrap from " + col.GetType().GetName());
        }
        return std::make_shared<ColumnTupleT<Columns...>>(VectorToTuple(std::move(col)));
    }

    static auto Wrap(Column&& col) { return Wrap(std::move(dynamic_cast<ColumnTuple&&>(col))); }

    // Helper to simplify integration with other APIs
    static auto Wrap(ColumnRef&& col) { return Wrap(std::move(*col->AsStrict<ColumnTuple>())); }

    ColumnRef Slice(size_t begin, size_t size) const override {
        return Wrap(ColumnTuple::Slice(begin, size));
    }

    ColumnRef CloneEmpty() const override { return Wrap(ColumnTuple::CloneEmpty()); }

    void Swap(Column& other) override {
        auto& col = dynamic_cast<ColumnTupleT<Columns...>&>(other);
        typed_columns_.swap(col.typed_columns_);
        ColumnTuple::Swap(other);
    }

private:
    template <typename T, size_t index = std::tuple_size_v<T>>
    inline void AppendTuple([[maybe_unused]] T value) {
        static_assert(index <= std::tuple_size_v<T>);
        static_assert(std::tuple_size_v<TupleOfColumns> == std::tuple_size_v<T>);
        if constexpr (index == 0) {
            return;
        } else {
            std::get<index - 1>(typed_columns_)->Append(std::move(std::get<index - 1>(value)));
            AppendTuple<T, index - 1>(std::move(value));
        }
    }

    template <typename T, size_t index = std::tuple_size_v<T>>
    inline static std::vector<ColumnRef> TupleToVector([[maybe_unused]] const T& value) {
        static_assert(index <= std::tuple_size_v<T>);
        if constexpr (index == 0) {
            std::vector<ColumnRef> result;
            result.reserve(std::tuple_size_v<T>);
            return result;
        } else {
            auto result = TupleToVector<T, index - 1>(value);
            result.push_back(std::get<index - 1>(value));
            return result;
        }
    }

    template <typename T, size_t column_index = std::tuple_size_v<TupleOfColumns>>
    inline static auto VectorToTuple([[maybe_unused]] T columns) {
        static_assert(column_index <= std::tuple_size_v<TupleOfColumns>);
        if constexpr (column_index == 0) {
            return std::make_tuple();
        } else {
            using ColumnType =
                typename std::tuple_element<column_index - 1, TupleOfColumns>::type::element_type;
            auto column = WrapColumn<ColumnType>(columns[column_index - 1]);
            return std::tuple_cat(std::move(VectorToTuple<T, column_index - 1>(std::move(columns))),
                                  std::make_tuple(std::move(column)));
        }
    }

    template <size_t column_index = std::tuple_size_v<TupleOfColumns>>
    inline auto GetTupleOfValues([[maybe_unused]]size_t index) const {
        static_assert(column_index <= std::tuple_size_v<TupleOfColumns>);
        if constexpr (column_index == 0) {
            return std::make_tuple();
        } else {
            return std::tuple_cat(
                std::move(GetTupleOfValues<column_index - 1>(index)),
                std::move(std::make_tuple(std::get<column_index - 1>(typed_columns_)->At(index))));
        }
    }

    TupleOfColumns typed_columns_;
};

}  // namespace clickhouse


Question: How do I load column data from an input stream into a ColumnTuple?

Answer: You can load column data from an input stream into a ColumnTuple using the LoadBody() function. It takes an InputStream pointer and the number of rows as arguments. The function returns a boolean value indicating the success of the operation. This is based on the comment "Loads column data from input stream."


Question: How can I clear the data in a ColumnTuple?

Answer: You can clear the data in a ColumnTuple by calling the Clear() function. It is an overridden function from the base Column class, as indicated by the comment "Clear column data."


Question: How do I get the number of rows in a ColumnTuple?

Answer: You can get the number of rows in a ColumnTuple by calling the Size() function. It returns the count of rows in the column, as mentioned in the comment "Returns count of rows in the column."


Question: What is the purpose of the ColumnTupleT class?

Answer: The ColumnTupleT class is a templated subclass of ColumnTuple that provides additional functionality and type safety. It allows creating a ColumnTuple with specific column types, accessing values using the At() function or operator[], appending values using the Append() function with a tuple argument, and wrapping a ColumnTuple or Column into a ColumnTupleT.


Question: How can you append elements to a ColumnIPv4 instance?

Answer:
The ColumnIPv4 class provides several methods to append elements:
a. Append an IP address as a string: void Append(const std::string& ip);
b. Append an IP address as a uint32_t value in host byte order: void Append(uint32_t ip);
c. Append an IP address as an in_addr value: void Append(in_addr ip);

#pragma once

#include "numeric.h"

struct in_addr;

namespace clickhouse {

class ColumnIPv4 : public Column {
public:
    using DataType = in_addr;
    using ValueType = in_addr;

    ColumnIPv4();
    /** Takes ownership of the data, expects ColumnUInt32.
     * Modifying memory pointed by `data` from outside is UB.
     *
     * TODO: deprecate and remove as it is too dangerous and error-prone.
     */
    explicit ColumnIPv4(ColumnRef data);

    explicit ColumnIPv4(std::vector<uint32_t>&& data);

    /// Appends one element to the column.
    void Append(const std::string& ip);

    /// @params ip numeric value with host byte order.
    void Append(uint32_t ip);

    ///
    void Append(in_addr ip);

    /// Returns element at given row number.
    in_addr At(size_t n) const;

    /// Returns element at given row number.
    in_addr operator [] (size_t n) const;

    std::string AsString(size_t n) const;

public:
    /// Increase the capacity of the column for large block insertion.
    void Reserve(size_t new_cap) override;

    /// Appends content of given column to the end of current one.
    void Append(ColumnRef column) override;

    /// Loads column data from input stream.
    bool LoadBody(InputStream* input, size_t rows) override;

    /// Saves column data to output stream.
    void SaveBody(OutputStream* output) override;

    /// Clear column data .
    void Clear() override;

    /// Returns count of rows in the column.
    size_t Size() const override;

    /// Makes slice of the current column.
    ColumnRef Slice(size_t begin, size_t len) const override;
    ColumnRef CloneEmpty() const override;
    void Swap(Column& other) override;

    ItemView GetItem(size_t index) const override;

private:
    std::shared_ptr<ColumnUInt32> data_;
};

}


Question: How can you access elements from a ColumnIPv4 instance?

Answer:
You can access elements from a ColumnIPv4 instance using the following methods:
a. Get the element at a given row number: in_addr At(size_t n) const;
b. Get the element at a given row number using the array operator: in_addr operator [] (size_t n) const;
c. Get the element as a string at a given row number: std::string AsString(size_t n) const;


Question: How can you append the content of another column to a ColumnIPv4 instance?

Answer: The void Append(ColumnRef column) method allows appending the content of another column to the end of the current ColumnIPv4 instance.


Question: How can you get the number of rows in a ColumnIPv4 instance?

Answer: The size_t Size() const method returns the count of rows (elements) in the column.


Question: How can you create a slice of a ColumnIPv4 instance?

Answer: The ColumnRef Slice(size_t begin, size_t len) const method allows creating a slice of the current column, starting from the specified begin position and containing len elements.


Question: What does the GetTypeMeta() function do?

Answer:
The GetTypeMeta() function takes a type name as input and returns the corresponding TypeAst::Meta enum value. It handles special type names such as "Array", "Null", "Nullable", "Tuple", "Enum8", "Enum16", "LowCardinality", "SimpleAggregateFunction", and "Map". For example:
<code>
if (name == "Array") {
    return TypeAst::Array;
}
</code>
If the input type name doesn't match any of the special cases, it returns TypeAst::Terminal.

#include "type_parser.h"

#include "clickhouse/exceptions.h"
#include "clickhouse/base/platform.h" // for _win_

#include <algorithm>
#include <cmath>
#include <map>
#include <mutex>
#include <unordered_map>

#if defined _win_
#include <string.h>
#else
#include <strings.h>
#endif

namespace clickhouse {

bool TypeAst::operator==(const TypeAst & other) const {
    return meta == other.meta
        && code == other.code
        && name == other.name
        && value == other.value
        && std::equal(elements.begin(), elements.end(), other.elements.begin(), other.elements.end());
}

static const std::unordered_map<std::string, Type::Code> kTypeCode = {
    { "Void",        Type::Void },
    { "Int8",        Type::Int8 },
    { "Int16",       Type::Int16 },
    { "Int32",       Type::Int32 },
    { "Int64",       Type::Int64 },
    { "Bool",        Type::UInt8 },
    { "UInt8",       Type::UInt8 },
    { "UInt16",      Type::UInt16 },
    { "UInt32",      Type::UInt32 },
    { "UInt64",      Type::UInt64 },
    { "Float32",     Type::Float32 },
    { "Float64",     Type::Float64 },
    { "String",      Type::String },
    { "FixedString", Type::FixedString },
    { "DateTime",    Type::DateTime },
    { "DateTime64",  Type::DateTime64 },
    { "Date",        Type::Date },
    { "Date32",      Type::Date32 },
    { "Array",       Type::Array },
    { "Nullable",    Type::Nullable },
    { "Tuple",       Type::Tuple },
    { "Enum8",       Type::Enum8 },
    { "Enum16",      Type::Enum16 },
    { "UUID",        Type::UUID },
    { "IPv4",        Type::IPv4 },
    { "IPv6",        Type::IPv6 },
    { "Int128",      Type::Int128 },
//    { "UInt128",      Type::UInt128 },
    { "Decimal",     Type::Decimal },
    { "Decimal32",   Type::Decimal32 },
    { "Decimal64",   Type::Decimal64 },
    { "Decimal128",  Type::Decimal128 },
    { "LowCardinality", Type::LowCardinality },
    { "Map",         Type::Map },
    { "Point",       Type::Point },
    { "Ring",        Type::Ring },
    { "Polygon",     Type::Polygon },
    { "MultiPolygon", Type::MultiPolygon },
};

template <typename L, typename R>
inline int CompateStringsCaseInsensitive(const L& left, const R& right) {
    int64_t size_diff = left.size() - right.size();
    if (size_diff != 0)
        return size_diff > 0 ? 1 : -1;

#if defined _win_
    return _strnicmp(left.data(), right.data(), left.size());
#else
    return strncasecmp(left.data(), right.data(), left.size());
#endif
}

static Type::Code GetTypeCode(const std::string& name) {
    auto it = kTypeCode.find(name);
    if (it != kTypeCode.end()) {
        return it->second;
    }

    return Type::Void;
}

static TypeAst::Meta GetTypeMeta(const StringView& name) {
    if (name == "Array") {
        return TypeAst::Array;
    }

    if (name == "Null") {
        return TypeAst::Null;
    }

    if (name == "Nullable") {
        return TypeAst::Nullable;
    }

    if (name == "Tuple") {
        return TypeAst::Tuple;
    }

    if (name == "Enum8" || name == "Enum16") {
        return TypeAst::Enum;
    }

    if (name == "LowCardinality") {
        return TypeAst::LowCardinality;
    }

    if (name == "SimpleAggregateFunction") {
        return TypeAst::SimpleAggregateFunction;
    }

    if (name == "Map") {
        return TypeAst::Map;
    }

    return TypeAst::Terminal;
}

bool ValidateAST(const TypeAst& ast) {
    // Void terminal that is not actually "void" produced when unknown type is encountered.
    if (ast.meta == TypeAst::Terminal
            && ast.code == Type::Void
            && CompateStringsCaseInsensitive(ast.name, std::string_view("void")) != 0)
        //throw UnimplementedError("Unsupported type: " + ast.name);
        return false;

    return true;
}

TypeParser::TypeParser(const StringView& name)
    : cur_(name.data())
    , end_(name.data() + name.size())
    , type_(nullptr)
{
}

TypeParser::~TypeParser() = default;

bool TypeParser::Parse(TypeAst* type) {
    type_ = type;
    open_elements_.push(type_);

    size_t processed_tokens = 0;
    do {
        const Token & token = NextToken();
        switch (token.type) {
            case Token::QuotedString:
            {
                type_->meta = TypeAst::Terminal;
                if (token.value.length() < 1)
                    type_->value_string = {};
                else
                    type_->value_string = token.value.substr(1, token.value.length() - 2).to_string();
                type_->code = Type::String;
                break;
            }
            case Token::Name:
                type_->meta = GetTypeMeta(token.value);
                type_->name = token.value.to_string();
                type_->code = GetTypeCode(type_->name);
                break;
            case Token::Number:
                type_->meta = TypeAst::Number;
                type_->value = std::stol(token.value.to_string());
                break;
            case Token::String:
                type_->meta = TypeAst::String;
                type_->value_string = std::string(token.value);
                break;
            case Token::LPar:
                type_->elements.emplace_back(TypeAst());
                open_elements_.push(type_);
                type_ = &type_->elements.back();
                break;
            case Token::RPar:
                type_ = open_elements_.top();
                open_elements_.pop();
                break;
            case Token::Assign:
            case Token::Comma:
                type_ = open_elements_.top();
                open_elements_.pop();
                type_->elements.emplace_back(TypeAst());
                open_elements_.push(type_);
                type_ = &type_->elements.back();
                break;
            case Token::EOS:
            {
                // Ubalanced braces, brackets, etc is an error.
                if (open_elements_.size() != 1)
                    return false;

                // Empty input string, no tokens produced
                if (processed_tokens == 0)
                    return false;

                return ValidateAST(*type);
            }
            case Token::Invalid:
                return false;
        }
        ++processed_tokens;
    } while (true);
}

TypeParser::Token TypeParser::NextToken() {
    for (; cur_ < end_; ++cur_) {
        switch (*cur_) {
            case ' ':
            case '\n':
            case '\t':
            case '\0':
                continue;
            case '=':
                return Token{Token::Assign, StringView(cur_++, 1)};
            case '(':
                return Token{Token::LPar, StringView(cur_++, 1)};
            case ')':
                return Token{Token::RPar, StringView(cur_++, 1)};
            case ',':
                return Token{Token::Comma, StringView(cur_++, 1)};
            case '\'':
            {
                const auto end_quote_length = 1;
                const StringView end_quote{cur_, end_quote_length};
                // Fast forward to the closing quote.
                const auto start = cur_++;
                for (; cur_ < end_ - end_quote_length; ++cur_) {
                    // TODO (nemkov): handle escaping ?
                    if (end_quote == StringView{cur_, end_quote_length}) {
                        cur_ += end_quote_length;

                        return Token{Token::QuotedString, StringView{start, cur_}};
                    }
                }
                return Token{Token::QuotedString, StringView(cur_++, 1)};
            }

            default: {
                const char* st = cur_;

                if (*cur_ == '\'') {
                    for (st = ++cur_; cur_ < end_; ++cur_) {
                        if (*cur_ == '\'') {
                            return Token{Token::String, StringView(st, cur_++ - st)};
                        }
                    }

                    return Token{Token::Invalid, StringView()};
                }

                if (isalpha(*cur_) || *cur_ == '_') {
                    for (; cur_ < end_; ++cur_) {
                        if (!isalpha(*cur_) && !isdigit(*cur_) && *cur_ != '_') {
                            break;
                        }
                    }

                    return Token{Token::Name, StringView(st, cur_)};
                }

                if (isdigit(*cur_) || *cur_ == '-') {
                    for (++cur_; cur_ < end_; ++cur_) {
                        if (!isdigit(*cur_)) {
                            break;
                        }
                    }

                    return Token{Token::Number, StringView(st, cur_)};
                }

                return Token{Token::Invalid, StringView()};
            }
        }
    }

    return Token{Token::EOS, StringView()};
}

const TypeAst* ParseTypeName(const std::string& type_name) {
    // Cache for type_name.
    // Usually we won't have too many type names in the cache, so do not try to
    // limit cache size.
    static std::map<std::string, TypeAst> ast_cache;
    static std::mutex lock;

    std::lock_guard<std::mutex> guard(lock);
    auto it = ast_cache.find(type_name);
    if (it != ast_cache.end()) {
        return &it->second;
    }

    auto& ast = ast_cache[type_name];
    if (TypeParser(type_name).Parse(&ast)) {
        return *
    }
    ast_cache.erase(type_name);
    return nullptr;
}

}


Question: How does the CompateStringsCaseInsensitive() function compare two strings case-insensitively?

Answer:
The CompateStringsCaseInsensitive() function compares two strings case-insensitively by first checking their size difference. If the sizes are different, it returns 1 if the left string is longer, or -1 if the right string is longer. If the sizes are equal, it uses platform-specific functions to perform a case-insensitive comparison:
<code>
#if defined _win_
    return _strnicmp(left.data(), right.data(), left.size());
#else
    return strncasecmp(left.data(), right.data(), left.size());
#endif
</code>
On Windows, it uses _strnicmp(), while on other platforms, it uses strncasecmp().


Question: What regular expression syntax is supported on Windows and Mac for death tests?

Answer:
On Windows and Mac, only a simple regex syntax implemented as part of Google Test is supported. As the comment explains:
"On other platforms (e.g. Windows or Mac), we only support a simple regex syntax implemented as part of Google Test.  This limited implementation should be enough most of the time when writing death tests; though it lacks many features you can find in PCRE or POSIX extended regex syntax."
The supported syntax is then documented in detail in the comments.

// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

//
// The Google C++ Testing and Mocking Framework (Google Test)
//
// This header file defines the public API for death tests.  It is
// #included by gtest.h so a user doesn't need to include this
// directly.
// GOOGLETEST_CM0001 DO NOT DELETE

#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
#define GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_

#include "gtest/internal/gtest-death-test-internal.h"

namespace testing {

// This flag controls the style of death tests.  Valid values are "threadsafe",
// meaning that the death test child process will re-execute the test binary
// from the start, running only a single death test, or "fast",
// meaning that the child process will execute the test logic immediately
// after forking.
GTEST_DECLARE_string_(death_test_style);

#if GTEST_HAS_DEATH_TEST

namespace internal {

// Returns a Boolean value indicating whether the caller is currently
// executing in the context of the death test child process.  Tools such as
// Valgrind heap checkers may need this to modify their behavior in death
// tests.  IMPORTANT: This is an internal utility.  Using it may break the
// implementation of death tests.  User code MUST NOT use it.
GTEST_API_ bool InDeathTestChild();

}  // namespace internal

// The following macros are useful for writing death tests.

// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
// executed:
//
//   1. It generates a warning if there is more than one active
//   thread.  This is because it's safe to fork() or clone() only
//   when there is a single thread.
//
//   2. The parent process clone()s a sub-process and runs the death
//   test in it; the sub-process exits with code 0 at the end of the
//   death test, if it hasn't exited already.
//
//   3. The parent process waits for the sub-process to terminate.
//
//   4. The parent process checks the exit code and error message of
//   the sub-process.
//
// Examples:
//
//   ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
//   for (int i = 0; i < 5; i++) {
//     EXPECT_DEATH(server.ProcessRequest(i),
//                  "Invalid request .* in ProcessRequest()")
//                  << "Failed to die on request " << i;
//   }
//
//   ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
//
//   bool KilledBySIGHUP(int exit_code) {
//     return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
//   }
//
//   ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
//
// The final parameter to each of these macros is a matcher applied to any data
// the sub-process wrote to stderr.  For compatibility with existing tests, a
// bare string is interpreted as a regular expression matcher.
//
// On the regular expressions used in death tests:
//
//   GOOGLETEST_CM0005 DO NOT DELETE
//   On POSIX-compliant systems (*nix), we use the <regex.h> library,
//   which uses the POSIX extended regex syntax.
//
//   On other platforms (e.g. Windows or Mac), we only support a simple regex
//   syntax implemented as part of Google Test.  This limited
//   implementation should be enough most of the time when writing
//   death tests; though it lacks many features you can find in PCRE
//   or POSIX extended regex syntax.  For example, we don't support
//   union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
//   repetition count ("x{5,7}"), among others.
//
//   Below is the syntax that we do support.  We chose it to be a
//   subset of both PCRE and POSIX extended regex, so it's easy to
//   learn wherever you come from.  In the following: 'A' denotes a
//   literal character, period (.), or a single \\ escape sequence;
//   'x' and 'y' denote regular expressions; 'm' and 'n' are for
//   natural numbers.
//
//     c     matches any literal character c
//     \\d   matches any decimal digit
//     \\D   matches any character that's not a decimal digit
//     \\f   matches \f
//     \\n   matches \n
//     \\r   matches \r
//     \\s   matches any ASCII whitespace, including \n
//     \\S   matches any character that's not a whitespace
//     \\t   matches \t
//     \\v   matches \v
//     \\w   matches any letter, _, or decimal digit
//     \\W   matches any character that \\w doesn't match
//     \\c   matches any literal character c, which must be a punctuation
//     .     matches any single character except \n
//     A?    matches 0 or 1 occurrences of A
//     A*    matches 0 or many occurrences of A
//     A+    matches 1 or many occurrences of A
//     ^     matches the beginning of a string (not that of each line)
//     $     matches the end of a string (not that of each line)
//     xy    matches x followed by y
//
//   If you accidentally use PCRE or POSIX extended regex features
//   not implemented by us, you will get a run-time failure.  In that
//   case, please try to rewrite your regular expression within the
//   above syntax.
//
//   This implementation is *not* meant to be as highly tuned or robust
//   as a compiled regex library, but should perform well enough for a
//   death test, which already incurs significant overhead by launching
//   a child process.
//
// Known caveats:
//
//   A "threadsafe" style death test obtains the path to the test
//   program from argv[0] and re-executes it in the sub-process.  For
//   simplicity, the current implementation doesn't search the PATH
//   when launching the sub-process.  This means that the user must
//   invoke the test program via a path that contains at least one
//   path separator (e.g. path/to/foo_test and
//   /absolute/path/to/bar_test are fine, but foo_test is not).  This
//   is rarely a problem as people usually don't put the test binary
//   directory in PATH.
//

// Asserts that a given `statement` causes the program to exit, with an
// integer exit status that satisfies `predicate`, and emitting error output
// that matches `matcher`.
# define ASSERT_EXIT(statement, predicate, matcher) \
    GTEST_DEATH_TEST_(statement, predicate, matcher, GTEST_FATAL_FAILURE_)

// Like `ASSERT_EXIT`, but continues on to successive tests in the
// test suite, if any:
# define EXPECT_EXIT(statement, predicate, matcher) \
    GTEST_DEATH_TEST_(statement, predicate, matcher, GTEST_NONFATAL_FAILURE_)

// Asserts that a given `statement` causes the program to exit, either by
// explicitly exiting with a nonzero exit code or being killed by a
// signal, and emitting error output that matches `matcher`.
# define ASSERT_DEATH(statement, matcher) \
    ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher)

// Like `ASSERT_DEATH`, but continues on to successive tests in the
// test suite, if any:
# define EXPECT_DEATH(statement, matcher) \
    EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher)

// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:

// Tests that an exit code describes a normal exit with a given exit code.
class GTEST_API_ ExitedWithCode {
 public:
  explicit ExitedWithCode(int exit_code);
  ExitedWithCode(const ExitedWithCode&) = default;
  void operator=(const ExitedWithCode& other) = delete;
  bool operator()(int exit_status) const;
 private:
  const int exit_code_;
};

# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
// Tests that an exit code describes an exit due to termination by a
// given signal.
// GOOGLETEST_CM0006 DO NOT DELETE
class GTEST_API_ KilledBySignal {
 public:
  explicit KilledBySignal(int signum);
  bool operator()(int exit_status) const;
 private:
  const int signum_;
};
# endif  // !GTEST_OS_WINDOWS

// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
// The death testing framework causes this to have interesting semantics,
// since the sideeffects of the call are only visible in opt mode, and not
// in debug mode.
//
// In practice, this can be used to test functions that utilize the
// LOG(DFATAL) macro using the following style:
//
// int DieInDebugOr12(int* sideeffect) {
//   if (sideeffect) {
//     *sideeffect = 12;
//   }
//   LOG(DFATAL) << "death";
//   return 12;
// }
//
// TEST(TestSuite, TestDieOr12WorksInDgbAndOpt) {
//   int sideeffect = 0;
//   // Only asserts in dbg.
//   EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
//
// #ifdef NDEBUG
//   // opt-mode has sideeffect visible.
//   EXPECT_EQ(12, sideeffect);
// #else
//   // dbg-mode no visible sideeffect.
//   EXPECT_EQ(0, sideeffect);
// #endif
// }
//
// This will assert that DieInDebugReturn12InOpt() crashes in debug
// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
// appropriate fallback value (12 in this case) in opt mode. If you
// need to test that a function has appropriate side-effects in opt
// mode, include assertions against the side-effects.  A general
// pattern for this is:
//
// EXPECT_DEBUG_DEATH({
//   // Side-effects here will have an effect after this statement in
//   // opt mode, but none in debug mode.
//   EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
// }, "death");
//
# ifdef NDEBUG

#  define EXPECT_DEBUG_DEATH(statement, regex) \
  GTEST_EXECUTE_STATEMENT_(statement, regex)

#  define ASSERT_DEBUG_DEATH(statement, regex) \
  GTEST_EXECUTE_STATEMENT_(statement, regex)

# else

#  define EXPECT_DEBUG_DEATH(statement, regex) \
  EXPECT_DEATH(statement, regex)

#  define ASSERT_DEBUG_DEATH(statement, regex) \
  ASSERT_DEATH(statement, regex)

# endif  // NDEBUG for EXPECT_DEBUG_DEATH
#endif  // GTEST_HAS_DEATH_TEST

// This macro is used for implementing macros such as
// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
// death tests are not supported. Those macros must compile on such systems
// if and only if EXPECT_DEATH and ASSERT_DEATH compile with the same parameters
// on systems that support death tests. This allows one to write such a macro on
// a system that does not support death tests and be sure that it will compile
// on a death-test supporting system. It is exposed publicly so that systems
// that have death-tests with stricter requirements than GTEST_HAS_DEATH_TEST
// can write their own equivalent of EXPECT_DEATH_IF_SUPPORTED and
// ASSERT_DEATH_IF_SUPPORTED.
//
// Parameters:
//   statement -  A statement that a macro such as EXPECT_DEATH would test
//                for program termination. This macro has to make sure this
//                statement is compiled but not executed, to ensure that
//                EXPECT_DEATH_IF_SUPPORTED compiles with a certain
//                parameter if and only if EXPECT_DEATH compiles with it.
//   regex     -  A regex that a macro such as EXPECT_DEATH would use to test
//                the output of statement.  This parameter has to be
//                compiled but not evaluated by this macro, to ensure that
//                this macro only accepts expressions that a macro such as
//                EXPECT_DEATH would accept.
//   terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
//                and a return statement for ASSERT_DEATH_IF_SUPPORTED.
//                This ensures that ASSERT_DEATH_IF_SUPPORTED will not
//                compile inside functions where ASSERT_DEATH doesn't
//                compile.
//
//  The branch that has an always false condition is used to ensure that
//  statement and regex are compiled (and thus syntactically correct) but
//  never executed. The unreachable code macro protects the terminator
//  statement from generating an 'unreachable code' warning in case
//  statement unconditionally returns or throws. The Message constructor at
//  the end allows the syntax of streaming additional messages into the
//  macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
# define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \
    GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
    if (::testing::internal::AlwaysTrue()) { \
      GTEST_LOG_(WARNING) \
          << "Death tests are not supported on this platform.\n" \
          << "Statement '" #statement "' cannot be verified."; \
    } else if (::testing::internal::AlwaysFalse()) { \
      ::testing::internal::RE::PartialMatch(".*", (regex)); \
      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
      terminator; \
    } else \
      ::testing::Message()

// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
// death tests are supported; otherwise they just issue a warning.  This is
// useful when you are combining death test assertions with normal test
// assertions in one test.
#if GTEST_HAS_DEATH_TEST
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
    EXPECT_DEATH(statement, regex)
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
    ASSERT_DEATH(statement, regex)
#else
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
    GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, )
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
    GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return)
#endif

}  // namespace testing

#endif  // GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_