def test_get_integer_from_hex_ascii_decimal(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        x = mp.FixedFormatMessageParser('3132333435363738', True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        # TEST N = VALUE
        result = x.get_integer_from_hex_ascii_decimal(4)
        self.assertEqual(result, 1234)
        self.assertEqual(x._cursor, 8)
        expected_calls = [
            call.l.info("Read '{}'", '31323334'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST N NOT SPECIFIED
        result = x.get_integer_from_hex_ascii_decimal()
        self.assertEqual(result, 5678)
        self.assertEqual(x._cursor, 16)
        expected_calls = [
            call.l.info("Read '{}'", '35363738'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_get_integer_from_hex_ascii_hex(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        x = mp.FixedFormatMessageParser('3132414243444546', True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        # TEST N = VALUE
        result = x.get_integer_from_hex_ascii_hex(4)
        self.assertEqual(result, 0x12AB)
        self.assertEqual(x._cursor, 8)
        expected_calls = [
            call.l.info("Read '{}'", '31324142'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST N NOT SPECIFIED
        result = x.get_integer_from_hex_ascii_hex()
        self.assertEqual(result, 0xCDEF)
        self.assertEqual(x._cursor, 16)
        expected_calls = [
            call.l.info("Read '{}'", '43444546'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_CONSTRUCTOR(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        # TEST DISABLE DEBUG
        x = mp.FixedFormatMessageParser('')
        self.assertEqual(x._message, '')
        self.assertFalse(x._enable_debug_mode)
        self.assertEqual(x._cursor, 0)
        self.assertEqual(x._cursor_last_parse, 0)
        self.assertIs(x._logger, mock_logger.return_value)
        expected_calls = [
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST ENABLE DEBUG
        msg = 'message'
        x = mp.FixedFormatMessageParser(msg, True)
        self.assertEqual(x._message, msg)
        self.assertTrue(x._enable_debug_mode)
        self.assertEqual(x._cursor, 0)
        self.assertEqual(x._cursor_last_parse, 0)
        self.assertIs(x._logger, mock_logger.return_value)
        expected_calls = [
            call.l.info("About to parse '{}'", msg),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_get_remaining_message(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        msg = '0123456789ABCDEF'
        x = mp.FixedFormatMessageParser(msg, True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        self.assertEqual(x.get_remaining_message(), '0123456789ABCDEF')
        self.assertEqual(x.get_remaining_message_length(), 16)

        x.get_characters(4)
        self.assertEqual(x.get_remaining_message(), '456789ABCDEF')
        self.assertEqual(x.get_remaining_message_length(), 12)

        x.get_characters()
        self.assertEqual(x.get_remaining_message(), '')
        self.assertEqual(x.get_remaining_message_length(), 0)

        expected_calls = [
            call.l.info("Read '{}'", '0123'),
            call.l.info("Read '{}'", '456789ABCDEF'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_assert_at_end_of_message(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        msg = 'message'
        x = mp.FixedFormatMessageParser(msg, True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        # TEST NOT AT END OF MESSAGE
        emsg = "ParseException: Unexpected text at end of message: ''   starting_here=>'message'"
        self.assertRaisesRegex(
            mp.ParseException,
            '^' + re.escape(emsg) + '$',
            x.assert_at_end_of_message
        )
        expected_calls = [
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST AT END OF MESSAGE
        x._cursor = len(msg)
        x.assert_at_end_of_message()
        expected_calls = [
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_get_hex_ascii(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        x = mp.FixedFormatMessageParser('4142434445464748', True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        # TEST N = VALUE
        result = x.get_hex_ascii(4)
        self.assertEqual(result, 'ABCD')
        self.assertEqual(x._cursor, 8)
        expected_calls = [
            call.l.info("Read '{}'", '41424344'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST N NOT SPECIFIED
        result = x.get_hex_ascii()
        self.assertEqual(result, 'EFGH')
        self.assertEqual(x._cursor, 16)
        expected_calls = [
            call.l.info("Read '{}'", '45464748'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_CONSTRUCTOR(self, mock_add_hex_bytes):
        mm = mock.Mock()
        mm.attach_mock(mock_add_hex_bytes, 'ahb')

        # TEST PARSER = NONE
        emsg = 'A FixedFormatMessageParser is required'
        self.assertRaisesRegex(
            AssertionError,
            '^' + re.escape(emsg) + '$',
            mp.BitMap, None
        )

        # TEST NO HEX_BYTES
        x = mp.BitMap(self.parser)
        self.assertIs(x._parser, self.parser)
        self.assertEqual(x._bits, {})
        self.assertEqual(x._next_bit, 1)
        self.assertEqual(x._scratchpad, {})
        expected_calls = [
            call.ahb(None),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST WITH HEX_BYTES
        x = mp.BitMap(self.parser, '8C031')
        self.assertIs(x._parser, self.parser)
        self.assertEqual(x._bits, {})
        self.assertEqual(x._next_bit, 1)
        self.assertEqual(x._scratchpad, {})
        expected_calls = [
            call.ahb('8C031'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_execute__null_executor(self):
        mm = mock.Mock()

        report_mock = mock.Mock()
        mm.attach_mock(report_mock, 'rm')

        parser = mp.FixedFormatMessageParser('3C5A3445556666aaaaaccccccdddddddffffffff')
        bitmap = mp.BitMap(parser, parser.get_characters(4))
        row_object = {}

        x = mp.BitMapExecutor()
        x.execute(bitmap, row_object)
        expected_calls = [
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
        self.assertEqual(parser.get_remaining_message(), '3445556666aaaaaccccccdddddddffffffff')
    def test_execute(self):
        mm = mock.Mock()

        report_mock = mock.Mock()
        mm.attach_mock(report_mock, 'rm')

        parser = mp.FixedFormatMessageParser('3C5A3445556666aaaaaccccccdddddddffffffff')
        bitmap = mp.BitMap(parser, parser.get_characters(4))
        row_object = {}

        def unexpected(bm, row, bit):
            report_mock.parse(bm, row, bit)

        def parse(bm, row, bit, expected):
            bitmap.get_parser().assert_equal(expected)
            report_mock.parse(bm, row, bit, expected)

        x = mp.BitMapExecutor()
        x.add_exec(1, lambda bitmap, row: unexpected(bitmap, row, 1))
        x.add_exec(2, lambda bitmap, row: unexpected(bitmap, row, 2))
        x.add_exec(3, lambda bitmap, row: parse(bitmap, row, 3, '3'))
        x.add_exec(4, lambda bitmap, row: parse(bitmap, row, 4, '44'))
        x.add_exec(5, lambda bitmap, row: parse(bitmap, row, 5, '555'))
        x.add_exec(6, lambda bitmap, row: parse(bitmap, row, 6, '6666'))
        x.add_exec(7, lambda bitmap, row: unexpected(bitmap, row, 7))
        x.add_exec(8, lambda bitmap, row: unexpected(bitmap, row, 8))
        x.add_exec(9, lambda bitmap, row: unexpected(bitmap, row, 9))
        x.add_exec(10, lambda bitmap, row: parse(bitmap, row, 10, 'aaaaa'))
        x.add_exec(11, lambda bitmap, row: unexpected(bitmap, row, 11))
        x.add_exec(12, lambda bitmap, row: parse(bitmap, row, 12, 'cccccc'))
        x.add_exec(13, lambda bitmap, row: parse(bitmap, row, 13, 'ddddddd'))
        x.add_exec(14, lambda bitmap, row: unexpected(bitmap, row, 14))
        x.add_exec(15, lambda bitmap, row: parse(bitmap, row, 15, 'ffffffff'))
        x.add_exec(16, lambda bitmap, row: unexpected(bitmap, row, 16))
        x.execute(bitmap, row_object)
        parser.assert_at_end_of_message()
        expected_calls = [
            call.rm.parse(bitmap, row_object, 3, '3'),
            call.rm.parse(bitmap, row_object, 4, '44'),
            call.rm.parse(bitmap, row_object, 5, '555'),
            call.rm.parse(bitmap, row_object, 6, '6666'),
            call.rm.parse(bitmap, row_object, 10, 'aaaaa'),
            call.rm.parse(bitmap, row_object, 12, 'cccccc'),
            call.rm.parse(bitmap, row_object, 13, 'ddddddd'),
            call.rm.parse(bitmap, row_object, 15, 'ffffffff'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test___str__(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        msg = 'message'
        x = mp.FixedFormatMessageParser(msg, True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        self.assertEqual(str(x), msg)
        x._cursor = 4
        self.assertEqual(str(x), msg[4:])
        expected_calls = [
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_get_integer_from_ascii_decimal_to_sentinel(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        x = mp.FixedFormatMessageParser('1234<02>5678', True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        result = x.get_integer_from_ascii_decimal_to_sentinel('<02>')
        self.assertEqual(result, 1234)
        self.assertEqual(x._cursor, 8)
        expected_calls = [
            call.l.info("Read '{}'", '1234'),
            call.l.info("Read '{}'", '<02>'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_get_integer_from_hex_ascii_hex_to_sentinel(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        x = mp.FixedFormatMessageParser('31324142<02>43444546', True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        result = x.get_integer_from_hex_ascii_hex_to_sentinel('<02>')
        self.assertEqual(result, 0x12AB)
        self.assertEqual(x._cursor, 12)
        expected_calls = [
            call.l.info("Read '{}'", '31324142'),
            call.l.info("Read '{}'", '<02>'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_get_cursor(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        msg1 = 'message1'
        x = mp.FixedFormatMessageParser(msg1, True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        self.assertEqual(x.get_cursor(), 0)
        x._cursor = 123
        self.assertEqual(x.get_cursor(), 123)

        expected_calls = [
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_get_message(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        msg = '0123456789ABCDEF'
        x = mp.FixedFormatMessageParser(msg, True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        self.assertIs(x.get_message(), msg)
        self.assertIs(x.get_message(-1), msg)
        self.assertIs(x.get_message(0), msg)
        self.assertEqual(x.get_message(7), '789ABCDEF')
        self.assertEqual(x._cursor, 0)
        expected_calls = [
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_get_characters(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        msg1 = 'message1'
        msg2 = 'message2'
        msg = msg1 + msg2
        x = mp.FixedFormatMessageParser(msg, True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        # TEST N = ZERO
        result = x.get_characters(0)
        self.assertEqual(result, '')
        self.assertEqual(x._cursor, 0)
        expected_calls = [
            call.l.info("Read '{}'", ''),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST N = NON-ZERO VALUE
        result = x.get_characters(len(msg1))
        self.assertEqual(result, msg1)
        self.assertEqual(x._cursor, len(msg1))
        expected_calls = [
            call.l.info("Read '{}'", msg1),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST N = None
        result = x.get_characters()
        self.assertEqual(result, msg2)
        self.assertEqual(x._cursor, len(msg))
        expected_calls = [
            call.l.info("Read '{}'", msg2),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        emsg = "ParseException: Attempt to read past end-of-message (cursor=16 length=5): 'message1message2'   starting_here=>''"
        self.assertRaisesRegex(
            mp.ParseException,
            '^' + re.escape(emsg) + '$',
            x.get_characters, 5
        )
        expected_calls = [
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_get_last_parse(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        msg = '0123456789ABCDEF'
        x = mp.FixedFormatMessageParser(msg, True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        self.assertEqual(x.get_last_parse(), '')

        x.assert_equal('0123')
        self.assertEqual(x.get_last_parse(), '0123')

        x.assert_equal('4567')
        x.assert_equal('89')
        x.assert_equal('A')
        self.assertEqual(x.get_last_parse(), '456789A')

        x.assert_equal('B')
        x.assert_equal('C')
        x.assert_equal('DEF')
        self.assertEqual(x.get_last_parse(), 'BCDEF')

        expected_calls = [
            call.l.info("Read '{}'", '0123'),
            call.l.info("Read '{}'", '4567'),
            call.l.info("Read '{}'", '89'),
            call.l.info("Read '{}'", 'A'),
            call.l.info("Read '{}'", 'B'),
            call.l.info("Read '{}'", 'C'),
            call.l.info("Read '{}'", 'DEF'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_get_characters_to_sentinel(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        msg1 = 'message1'
        sentinel1 = '<1>'
        msg2 = 'message2'
        sentinel2 = '<2>'
        msg = msg1 + sentinel1 + msg2 + sentinel2
        x = mp.FixedFormatMessageParser(msg, True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        # TEST HAPPY PATH
        result = x.get_characters_to_sentinel(sentinel1)
        self.assertEqual(result, msg1)
        self.assertEqual(x._cursor, len(msg1 + sentinel1))
        expected_calls = [
            call.l.info("Read '{}'", 'message1'),
            call.l.info("Read '{}'", '<1>'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST SENTINEL = None
        emsg = "ParseException: Attempt to use None sentinel: 'message1<1>'   starting_here=>'message2<2>'"
        self.assertRaisesRegex(
            mp.ParseException,
            '^' + re.escape(emsg) + '$',
            x.get_characters_to_sentinel, None
        )
        expected_calls = [
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST SENTINEL NOT FOUND
        emsg = "ParseException: Could not find sentinel '<x>': 'message1<1>'   starting_here=>'message2<2>'"
        self.assertRaisesRegex(
            mp.ParseException,
            '^' + re.escape(emsg) + '$',
            x.get_characters_to_sentinel, '<x>'
        )
        expected_calls = [
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_assert_equal(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        msg = 'message'
        x = mp.FixedFormatMessageParser(msg, True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        # TEST EQUAL - value = None
        emsg = "ParseException: Attempt to compare using None: ''   starting_here=>'message'"
        self.assertRaisesRegex(
            mp.ParseException,
            '^' + re.escape(emsg) + '$',
            x.assert_equal, None
        )
        expected_calls = [
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST NOT-EQUAL
        emsg = "ParseException: Expected value 'sam': ''   starting_here=>'message'"
        self.assertRaisesRegex(
            mp.ParseException,
            '^' + re.escape(emsg) + '$',
            x.assert_equal, 'sam'
        )
        expected_calls = [
            call.l.info("Read '{}'", 'mes'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST EQUAL
        x._cursor = 0
        x.assert_equal(msg)
        self.assertEqual(x._cursor, len(msg))
        expected_calls = [
            call.l.info("Read '{}'", 'message'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)
    def test_assert_blank(self, mock_logger):
        mm = mock.Mock()

        mock_logger.return_value = mock.Mock()
        mm.attach_mock(mock_logger.return_value, 'l')

        msg = '   message'
        x = mp.FixedFormatMessageParser(msg, True)
        # Clear mock calls from constructor
        mm.mock_calls.clear()

        # TEST NOT BLANK - N = None
        emsg = "ParseException: Expected blank field of length 10: ''   starting_here=>'   message'"
        self.assertRaisesRegex(
            mp.ParseException,
            '^' + re.escape(emsg) + '$',
            x.assert_blank
        )
        expected_calls = [
            call.l.info("Read '{}'", '   message'),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST BLANK - N = 0
        x._cursor = 0
        x.assert_blank(0)
        self.assertEqual(x._cursor, 0)
        expected_calls = [
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)

        # TEST BLANK - N = 3
        x._cursor = 0
        x.assert_blank(3)
        self.assertEqual(x._cursor, 3)
        expected_calls = [
            call.l.info("Read '{}'", '   '),
        ]
        verify_mock_calls(self, mm.mock_calls, expected_calls)