"""Unit tests for base41.

Copyright: (c) Jazzy Services Limited 2017
License file: ../LICENSE

"""
import sys
import unittest

import context
import base41


class Test_B41Encoder(unittest.TestCase):

    def test_sanity(I):
        'Test the encoder with a standard byte string.'
        datum = b'John'
        sut = [byt for byt in base41.B41Encoder(datum)]
        expected = [0x4f, 0x6d, 0x6b, 0x32, 0x55, 0x6f]
        I.assertEqual(sut, expected)

    def test_sanity_lo_trailing(I):
        'Test the encoder with a low trailing byte.'
        datum = b'John!'
        sut = [byt for byt in base41.B41Encoder(datum)]
        expected = [0x4f, 0x6d, 0x6b, 0x32, 0x55, 0x6f, 0x51]
        I.assertEqual(sut, expected)

    def test_sanity_hi_trailing(I):
        'Test the encoder with a high trailing byte.'
        datum = b'John)'
        sut = [byt for byt in base41.B41Encoder(datum)]
        expected = [0x4f, 0x6d, 0x6b, 0x32, 0x55, 0x6f, 0x30, 0x31]
        I.assertEqual(sut, expected)

    def test_minimum(I):
        'Test the encoder with nulls.'
        N = 100
        datum = N * [0, 0]
        sut = [byt for byt in base41.B41Encoder(datum)]
        expected = N * [0x30, 0x30, 0x30]
        I.assertEqual(sut, expected)

    def test_minimum_trailing(I):
        'Test the encoder with an odd number of nulls.'
        datum = [0,0,0]
        sut = [byt for byt in base41.B41Encoder(datum)]
        expected = [0x30, 0x30, 0x30, 0x30]
        I.assertEqual(sut, expected)

    def test_maximum(I):
        'Test the encoder with 0xff.'
        N = 100
        datum = N * [0xff,0xff]
        sut = [byt for byt in base41.B41Encoder(datum)]
        expected = N * [0x41, 0x58, 0x56]   # AXV
        I.assertEqual(sut, expected)

    def test_maximum_trailing(I):
        'Test the encoder with an odd number of 0xff.'
        datum = [0xff,0xff,0xff]
        sut = [byt for byt in base41.B41Encoder(datum)]
        expected = [0x41, 0x58, 0x56, 0x39, 0x36]   # AXV-96
        I.assertEqual(sut, expected)

    def test_pair_boundaries(I):
        'Test the encoder on base41 boundaries.'
        data = [
            ([  0,   0], [0x30, 0x30, 0x30]), # 000
            ([  0,  40], [0x58, 0x30, 0x30]), # X00
            ([  0,  41], [0x30, 0x31, 0x30]), # 010
            ([  6, 104], [0x30, 0x58, 0x30]), # 0X0
            ([  6, 144], [0x58, 0x58, 0x30]), # XX0
            ([  6, 145], [0x30, 0x30, 0x31]), # 001
            ([249, 134], [0x30, 0x30, 0x56]), # 00V
            ([255, 238], [0x30, 0x58, 0x56]), # 0XV
            ([255, 255], [0x41, 0x58, 0x56]), # AXV
        ]
        for datum, expected in data:
            sut = [byt for byt in base41.B41Encoder(datum)]
            I.assertEqual(sut, expected)

    def test_singles(I):
        'Test the encoder using single bytes.'
        for datum, expected in zip(range(41), base41.ALFA):
            sut = [byt for byt in base41.B41Encoder([datum])]
            I.assertEqual(sut, [expected])


class Test_b41encode(unittest.TestCase):

    def test_sanity(I):
        'Test the encoder with a standard byte string.'
        datum = b'John'
        sut = base41.b41encode(datum)
        I.assertEqual(sut, b'Omk2Uo')

    def test_sanity_lo_trailing(I):
        'Test the encoder with a low trailing byte.'
        datum = b'John!'
        sut = base41.b41encode(datum)
        I.assertEqual(sut, b'Omk2UoQ')

    def test_sanity_hi_trailing(I):
        'Test the encoder with a high trailing byte.'
        datum = b'John)'
        sut = base41.b41encode(datum)
        I.assertEqual(sut, b'Omk2Uo01')

    def test_minimum(I):
        'Test the encoder with nulls.'
        N = 100
        datum = N * [0, 0]
        sut = base41.b41encode(datum)
        expected = N * b'000'
        I.assertEqual(sut, expected)

    def test_minimum_trailing(I):
        'Test the encoder with an odd number of nulls.'
        datum = [0,0,0]
        sut = base41.b41encode(datum)
        I.assertEqual(sut, b'0000')

    def test_maximum(I):
        'Test the encoder with 0xff.'
        N = 100
        datum = N * [0xff,0xff]
        sut = base41.b41encode(datum)
        expected = N * b'AXV'
        I.assertEqual(sut, expected)

    def test_maximum_trailing(I):
        'Test the encoder with an odd number of 0xff.'
        datum = [0xff,0xff,0xff]
        sut = base41.b41encode(datum)
        expected = b'AXV96'
        I.assertEqual(sut, expected)

    def test_pair_boundaries(I):
        'Test the encoder on base41 boundaries.'
        data = [
            
([  0,   0], b'000'),
            ([  0,  40], b'X00'),
            ([  0,  41], b'010'),
            ([  6, 104], b'0X0'),
            ([  6, 144], b'XX0'),
            ([  6, 145], b'001'),
            ([249, 134], b'00V'),
            ([255, 238], b'0XV'),
            ([255, 255], b'AXV'),
        ]
        for datum, expected in data:
            
sut = base41.b41encode(datum)
            I.assertEqual(sut, expected)


class Test_b41string(unittest.TestCase):

    def test_sanity(I):
        'Test the encoder with a standard byte string.'
        datum = b'John'
        sut = base41.b41string(datum)
        I.assertEqual(sut, 'Omk2Uo')

    def test_sanity_lo_trailing(I):
        'Test the encoder with a low trailing byte.'
        datum = b'John!'
        sut = base41.b41string(datum)
        I.assertEqual(sut, 'Omk2UoQ')

    def test_sanity_hi_trailing(I):
        'Test the encoder with a high trailing byte.'
        datum = b'John)'
        sut = base41.b41string(datum)
        I.assertEqual(sut, 'Omk2Uo01')

    def test_minimum(I):
        'Test the encoder with nulls.'
        N = 100
        datum = N * [0, 0]
        sut = base41.b41string(datum)
        expected = N * '000'
        I.assertEqual(sut, expected)

    def test_minimum_trailing(I):
        'Test the encoder with an odd number of nulls.'
        datum = [0,0,0]
        sut = base41.b41string(datum)
        I.assertEqual(sut, '0000')

    def test_maximum(I):
        'Test the encoder with 0xff.'
        N = 100
        datum = N * [0xff,0xff]
        sut = base41.b41string(datum)
        expected = N * 'AXV'
        I.assertEqual(sut, expected)

    def test_maximum_trailing(I):
        'Test the encoder with an odd number of 0xff.'
        datum = [0xff,0xff,0xff]
        sut = base41.b41string(datum)
        expected = 'AXV96'
        I.assertEqual(sut, expected)

    def test_pair_boundaries(I):
        'Test the encoder on base41 boundaries.'
        data = [
            ([  0,   0], '000'),
            ([  0,  40], 'X00'),
            ([  0,  41], '010'),
            ([  6, 104], '0X0'),
            ([  6, 144], 'XX0'),
            ([  6, 145], '001'),
            ([249, 134], '00V'),
            ([255, 238], '0XV'),
            ([255, 255], 'AXV'),
        ]
        for datum, expected in data:
            sut = base41.b41string(datum)
            I.assertEqual(sut, expected)


#   _
# _| |________________________________________________________________________

class Test_B41Decoder(unittest.TestCase):

    def test_sanity(I):
        'Test the decoder with a standard byte string.'
        datum = [0x4f, 0x6d, 0x6b, 0x32, 0x55, 0x6f]
        sut = [byt for byt in base41.B41Decoder(datum)]
        expected = [0x4a, 0x6f, 0x68, 0x6e]
        I.assertEqual(sut, expected)

    def test_sanity_lo_trailing(I):
        'Test the decoder with a low trailing byte.'
        datum = [0x4f, 0x6d, 0x6b, 0x32, 0x55, 0x6f, 0x51]
        sut = [byt for byt in base41.B41Decoder(datum)]
        expected = [0x4a, 0x6f, 0x68, 0x6e, 0x21]
        I.assertEqual(sut, expected)

    def test_sanity_hi_trailing(I):
        'Test the decoder with a high trailing byte.'
        datum = [0x4f, 0x6d, 0x6b, 0x32, 0x55, 0x6f, 0x30, 0x31]
        sut = [byt for byt in base41.B41Decoder(datum)]
        expected = [0x4a, 0x6f, 0x68, 0x6e, 0x29]
        I.assertEqual(sut, expected)

    def test_minimum(I):
        'Test the decoder with nulls.'
        N = 100
        datum = N * [0x30, 0x30, 0x30]
        sut = [byt for byt in base41.B41Decoder(datum)]
        expected = N * [0, 0]
        I.assertEqual(sut, expect