Example #1
0
 def test_tap_file(self):
     data = [1, 2, 4]
     tap_data = create_tap_header_block('test_tap01', 32768, len(data))
     tap_data.extend(create_tap_data_block(data))
     tap_data.extend(create_tap_header_block('numbers_01', data_type=1))
     tap_data.extend(create_tap_data_block([8, 16, 32]))
     tapfile = self.write_bin_file(tap_data, suffix='.tap')
     output, error = self.run_tapinfo(tapfile)
     self.assertEqual(error, '')
     exp_output = """
         1:
           Type: Header block
           Bytes: test_tap01
           CODE: 32768,3
           Length: 19
           Data: 0, 3, 116, 101, 115, 116, 95 ... 3, 0, 0, 128, 0, 0, 173
         2:
           Type: Data block
           Length: 5
           Data: 255, 1, 2, 4, 7
         3:
           Type: Header block
           Number array: numbers_01
           Length: 19
           Data: 0, 1, 110, 117, 109, 98, 101 ... 0, 0, 0, 0, 0, 0, 47
         4:
           Type: Data block
           Length: 5
           Data: 255, 8, 16, 32, 56
     """
     self.assertEqual(dedent(exp_output).lstrip(), output)
Example #2
0
 def test_tap_file(self):
     data = [1, 2, 4]
     tap_data = create_tap_header_block("test_tap", 32768, len(data))
     tap_data.extend(create_tap_data_block(data))
     tap_data.extend(create_tap_header_block("numbers", data_type=1))
     tap_data.extend(create_tap_data_block([8, 16, 32]))
     tapfile = self.write_bin_file(tap_data, suffix=".tap")
     output, error = self.run_tapinfo(tapfile)
     self.assertEqual(len(error), 0)
     exp_output = [
         "1:",
         "  Type: Header block",
         "  Bytes: test_tap",
         "  CODE: 32768,3",
         "  Length: 19",
         "  Data: 0, 3, 116, 101, 115, 116, 95 ... 3, 0, 0, 128, 0, 0, 172",
         "2:",
         "  Type: Data block",
         "  Length: 5",
         "  Data: 255, 1, 2, 4, 7",
         "3:",
         "  Type: Header block",
         "  Number array: numbers",
         "  Length: 19",
         "  Data: 0, 1, 110, 117, 109, 98, 101 ... 0, 0, 0, 0, 0, 0, 81",
         "4:",
         "  Type: Data block",
         "  Length: 5",
         "  Data: 255, 8, 16, 32, 56",
     ]
     self.assertEqual(exp_output, output)
Example #3
0
 def test_tap_file(self):
     data = [1, 2, 4]
     tap_data = create_tap_header_block('test_tap01', 32768, len(data))
     tap_data.extend(create_tap_data_block(data))
     tap_data.extend(create_tap_header_block('numbers_01', data_type=1))
     tap_data.extend(create_tap_data_block([8, 16, 32]))
     tapfile = self.write_bin_file(tap_data, suffix='.tap')
     output, error = self.run_tapinfo(tapfile)
     self.assertEqual(error, '')
     exp_output = """
         1:
           Type: Header block
           Bytes: test_tap01
           CODE: 32768,3
           Length: 19
           Data: 0, 3, 116, 101, 115, 116, 95 ... 3, 0, 0, 128, 0, 0, 173
         2:
           Type: Data block
           Length: 5
           Data: 255, 1, 2, 4, 7
         3:
           Type: Header block
           Number array: numbers_01
           Length: 19
           Data: 0, 1, 110, 117, 109, 98, 101 ... 0, 0, 0, 0, 0, 0, 47
         4:
           Type: Data block
           Length: 5
           Data: 255, 8, 16, 32, 56
     """
     self.assertEqual(dedent(exp_output).lstrip(), output)
Example #4
0
 def test_tap_file(self):
     data = [1, 2, 4]
     tap_data = create_tap_header_block('test_tap', 32768, len(data))
     tap_data.extend(create_tap_data_block(data))
     tap_data.extend(create_tap_header_block('numbers', data_type=1))
     tap_data.extend(create_tap_data_block([8, 16, 32]))
     tapfile = self.write_bin_file(tap_data, suffix='.tap')
     output, error = self.run_tapinfo(tapfile)
     self.assertEqual(len(error), 0)
     exp_output = [
         '1:',
         '  Type: Header block',
         '  Bytes: test_tap',
         '  CODE: 32768,3',
         '  Length: 19',
         '  Data: 0, 3, 116, 101, 115, 116, 95 ... 3, 0, 0, 128, 0, 0, 172',
         '2:',
         '  Type: Data block',
         '  Length: 5',
         '  Data: 255, 1, 2, 4, 7',
         '3:',
         '  Type: Header block',
         '  Number array: numbers',
         '  Length: 19',
         '  Data: 0, 1, 110, 117, 109, 98, 101 ... 0, 0, 0, 0, 0, 0, 81',
         '4:',
         '  Type: Data block',
         '  Length: 5',
         '  Data: 255, 8, 16, 32, 56'
     ]
     self.assertEqual(exp_output, output)
Example #5
0
    def test_standard_load_ignores_headerless_block(self):
        code_start = 16384
        code = [2]
        blocks = [
            create_tap_header_block(start=code_start),
            create_tap_data_block(code),
            create_tap_data_block([23])
        ]

        tapfile = self._write_tap(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        output, error = self.run_tap2sna('--force {} {}'.format(tapfile, z80file))
        self.assertEqual(error, '')
        snapshot = get_snapshot(z80file)
        self.assertEqual(code, snapshot[code_start:code_start + len(code)])
Example #6
0
    def test_standard_load_ignores_headerless_block(self):
        code_start = 16384
        code = [2]
        blocks = [
            create_tap_header_block(start=code_start),
            create_tap_data_block(code),
            create_tap_data_block([23])
        ]

        tapfile = self._write_tap(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        output, error = self.run_tap2sna('--force {} {}'.format(tapfile, z80file))
        self.assertEqual(error, '')
        snapshot = get_snapshot(z80file)
        self.assertEqual(code, snapshot[code_start:code_start + len(code)])
Example #7
0
 def test_reg(self):
     block = create_tap_data_block([1])
     tapfile = self._write_tap([block])
     z80file = self.write_bin_file(suffix='.z80')
     reg_dicts = (
         {'^a': 1, '^b': 2, '^c': 3, '^d': 4, '^e': 5, '^f': 6, '^h': 7, '^l': 8},
         {'a': 9, 'b': 10, 'c': 11, 'd': 12, 'e': 13, 'f': 14, 'h': 15, 'l': 16, 'r': 129},
         {'^bc': 258, '^de': 515, '^hl': 65534, 'bc': 259, 'de': 516, 'hl': 65533},
         {'i': 13, 'ix': 1027, 'iy': 1284, 'pc': 1541, 'r': 23, 'sp': 32769}
     )
     for reg_dict in reg_dicts:
         reg_options = ' '.join(['--reg {}={}'.format(r, v) for r, v in reg_dict.items()])
         output, error = self.run_tap2sna('--force --ram load=1,16384 {} {} {}'.format(reg_options, tapfile, z80file))
         self.assertEqual(error, '')
         with open(z80file, 'rb') as f:
             z80_header = f.read(34)
         for reg, exp_value in reg_dict.items():
             offset = Z80_REGISTERS[reg]
             size = len(reg) - 1 if reg.startswith('^') else len(reg)
             if size == 1:
                 value = z80_header[offset]
             else:
                 value = z80_header[offset] + 256 * z80_header[offset + 1]
             self.assertEqual(value, exp_value)
             if reg == 'r' and exp_value & 128:
                 self.assertEqual(z80_header[12] & 1, 1)
Example #8
0
 def _test_bad_spec(self, option, exp_error):
     odir = self.make_directory()
     tapfile = self._write_tap([create_tap_data_block([1])])
     z80fname = 'test.z80'
     with self.assertRaises(SkoolKitError) as cm:
         self.run_tap2sna('--ram load=1,16384 {} -d {} {} {}'.format(option, odir, tapfile, z80fname))
     self.assertEqual(cm.exception.args[0], 'Error while getting snapshot {}: {}'.format(z80fname, exp_error))
Example #9
0
 def test_no_clobber(self):
     block = create_tap_data_block([0])
     tapfile = self._write_tap([block])
     z80file = self.write_bin_file(suffix='.z80')
     output, error = self.run_tap2sna('--ram load=1,16384 {} {}'.format(tapfile, z80file))
     self.assertTrue(output.startswith('{}: file already exists; use -f to overwrite\n'.format(z80file)))
     self.assertEqual(error, '')
Example #10
0
 def test_reg(self):
     block = create_tap_data_block([1])
     tapfile = self._write_tap([block])
     z80file = self.write_bin_file(suffix='.z80')
     reg_dicts = (
         {'^a': 1, '^b': 2, '^c': 3, '^d': 4, '^e': 5, '^f': 6, '^h': 7, '^l': 8},
         {'a': 9, 'b': 10, 'c': 11, 'd': 12, 'e': 13, 'f': 14, 'h': 15, 'l': 16, 'r': 129},
         {'^bc': 258, '^de': 515, '^hl': 65534, 'bc': 259, 'de': 516, 'hl': 65533},
         {'i': 13, 'ix': 1027, 'iy': 1284, 'pc': 1541, 'r': 23, 'sp': 32769}
     )
     for reg_dict in reg_dicts:
         reg_options = ' '.join(['--reg {}={}'.format(r, v) for r, v in reg_dict.items()])
         output, error = self.run_tap2sna('--force --ram load=1,16384 {} {} {}'.format(reg_options, tapfile, z80file))
         self.assertEqual(error, '')
         with open(z80file, 'rb') as f:
             z80_header = bytearray(f.read(34))
         for reg, exp_value in reg_dict.items():
             offset = Z80_REGISTERS[reg]
             size = len(reg) - 1 if reg.startswith('^') else len(reg)
             if size == 1:
                 value = z80_header[offset]
             else:
                 value = z80_header[offset] + 256 * z80_header[offset + 1]
             self.assertEqual(value, exp_value)
             if reg == 'r' and exp_value & 128:
                 self.assertEqual(z80_header[12] & 1, 1)
Example #11
0
    def test_default_register_values(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        exp_reg_values = {
            'a': 0,
            'f': 0,
            'bc': 0,
            'de': 0,
            'hl': 0,
            'i': 63,
            'r': 0,
            '^bc': 0,
            '^de': 0,
            '^hl': 0,
            'ix': 0,
            'iy': 23610,
            'sp': 0,
            'pc': 0
        }

        output, error = self.run_tap2sna(
            '--force --ram load=1,16384 {} {}'.format(tapfile, z80file))
        self.assertEqual(error, '')
        with open(z80file, 'rb') as f:
            z80_header = f.read(34)
        for reg, exp_value in exp_reg_values.items():
            offset = Z80_REGISTERS[reg]
            size = len(reg) - 1 if reg.startswith('^') else len(reg)
            if size == 1:
                value = z80_header[offset]
            else:
                value = z80_header[offset] + 256 * z80_header[offset + 1]
            self.assertEqual(value, exp_value)
Example #12
0
 def test_no_clobber(self):
     block = create_tap_data_block([0])
     tapfile = self._write_tap([block])
     z80file = self.write_bin_file(suffix='.z80')
     output, error = self.run_tap2sna('--ram load=1,16384 {} {}'.format(tapfile, z80file))
     self.assertEqual(output[0], '{}: file already exists; use -f to overwrite'.format(z80file))
     self.assertEqual(error, '')
Example #13
0
 def _test_bad_spec(self, option, exp_error):
     odir = self.make_directory()
     tapfile = self._write_tap([create_tap_data_block([1])])
     z80fname = 'test.z80'
     with self.assertRaises(SkoolKitError) as cm:
         self.run_tap2sna('--ram load=1,16384 {} -d {} {} {}'.format(option, odir, tapfile, z80fname))
     self.assertEqual(cm.exception.args[0], 'Error while getting snapshot {}: {}'.format(z80fname, exp_error))
Example #14
0
 def test_option_B_tap(self):
     prog = [10] * 10
     tap_data = create_tap_data_block(prog)
     tapfile = self.write_bin_file(tap_data, suffix='.tap')
     exp_snapshot = [0] * 23755 + prog
     output, error = self.run_tapinfo('-B 1 {}'.format(tapfile))
     self.assertEqual(error, '')
     self.assertEqual(output, 'BASIC DONE!\n')
     self.assertEqual(exp_snapshot, mock_basic_lister.snapshot)
Example #15
0
 def test_option_B_tap(self):
     prog = [10] * 10
     tap_data = create_tap_data_block(prog)
     tapfile = self.write_bin_file(tap_data, suffix='.tap')
     exp_snapshot = [0] * 23755 + prog
     output, error = self.run_tapinfo('-B 1 {}'.format(tapfile))
     self.assertEqual(error, '')
     self.assertEqual(['BASIC DONE!'], output)
     self.assertEqual(exp_snapshot, mock_basic_lister.snapshot)
Example #16
0
    def test_standard_load_from_tap_file(self):
        basic_data = [1, 2, 3]
        code_start = 32768
        code = [4, 5]
        blocks = [
            create_tap_header_block(data_type=0),
            create_tap_data_block(basic_data),
            create_tap_header_block(start=code_start),
            create_tap_data_block(code)
        ]

        tapfile = self._write_tap(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        output, error = self.run_tap2sna('--force {} {}'.format(tapfile, z80file))
        self.assertEqual(error, '')
        snapshot = get_snapshot(z80file)
        self.assertEqual(basic_data, snapshot[23755:23755 + len(basic_data)])
        self.assertEqual(code, snapshot[code_start:code_start + len(code)])
Example #17
0
    def test_standard_load_from_tap_file(self):
        basic_data = [1, 2, 3]
        code_start = 32768
        code = [4, 5]
        blocks = [
            create_tap_header_block(data_type=0),
            create_tap_data_block(basic_data),
            create_tap_header_block(start=code_start),
            create_tap_data_block(code)
        ]

        tapfile = self._write_tap(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        output, error = self.run_tap2sna('--force {} {}'.format(tapfile, z80file))
        self.assertEqual(error, '')
        snapshot = get_snapshot(z80file)
        self.assertEqual(basic_data, snapshot[23755:23755 + len(basic_data)])
        self.assertEqual(code, snapshot[code_start:code_start + len(code)])
Example #18
0
 def test_option_d(self):
     odir = '{}/tap2sna'.format(self.make_directory())
     block = create_tap_data_block([0])
     tapfile = self._write_tap([block])
     z80_fname = 'test.z80'
     for option in ('-d', '--output-dir'):
         output, error = self.run_tap2sna('{} {} {} {}'.format(option, odir, tapfile, z80_fname))
         self.assertEqual(len(error), 0)
         self.assertTrue(os.path.isfile(os.path.join(odir, z80_fname)))
Example #19
0
 def test_load_nonexistent_block(self):
     tapfile = self._write_tap([create_tap_data_block([1])])
     block_num = 2
     with self.assertRaises(SkoolKitError) as cm:
         self.run_tap2sna('--ram load={},16384 {} {}/test.z80'.format(
             block_num, tapfile, self.make_directory()))
     self.assertEqual(
         cm.exception.args[0],
         'Error while getting snapshot test.z80: Block {} not found'.format(
             block_num))
Example #20
0
 def test_reg_hex_value(self):
     odir = self.make_directory()
     tapfile = self._write_tap([create_tap_data_block([1])])
     z80fname = 'test.z80'
     reg_value = 35487
     output, error = self.run_tap2sna('--ram load=1,16384 --reg bc=${:x} -d {} {} {}'.format(reg_value, odir, tapfile, z80fname))
     self.assertEqual(error, '')
     with open(os.path.join(odir, z80fname), 'rb') as f:
         z80_header = bytearray(f.read(4))
     self.assertEqual(z80_header[2] + 256 * z80_header[3], reg_value)
Example #21
0
 def test_state_im(self):
     block = create_tap_data_block([0])
     tapfile = self._write_tap([block])
     z80file = self.write_bin_file(suffix='.z80')
     im_value = 2
     output, error = self.run_tap2sna('--force --ram load=1,16384 --state im={} {} {}'.format(im_value, tapfile, z80file))
     self.assertEqual(error, '')
     with open(z80file, 'rb') as f:
         z80_header = bytearray(f.read(30))
     self.assertEqual(z80_header[29] & 3, im_value)
Example #22
0
 def test_state_border(self):
     block = create_tap_data_block([0])
     tapfile = self._write_tap([block])
     z80file = self.write_bin_file(suffix='.z80')
     border = 4
     output, error = self.run_tap2sna('--force --ram load=1,16384 --state border={} {} {}'.format(border, tapfile, z80file))
     self.assertEqual(error, '')
     with open(z80file, 'rb') as f:
         z80_header = bytearray(f.read(13))
     self.assertEqual((z80_header[12] // 2) & 7, border)
Example #23
0
 def test_reg_0x_hex_value(self):
     odir = self.make_directory()
     tapfile = self._write_tap([create_tap_data_block([1])])
     z80fname = 'test.z80'
     reg_value = 54873
     output, error = self.run_tap2sna('--ram load=1,16384 --reg hl=0x{:x} -d {} {} {}'.format(reg_value, odir, tapfile, z80fname))
     self.assertEqual(error, '')
     with open(os.path.join(odir, z80fname), 'rb') as f:
         z80_header = f.read(6)
     self.assertEqual(z80_header[4] + 256 * z80_header[5], reg_value)
Example #24
0
 def test_state_border(self):
     block = create_tap_data_block([0])
     tapfile = self._write_tap([block])
     z80file = self.write_bin_file(suffix='.z80')
     border = 4
     output, error = self.run_tap2sna('--force --ram load=1,16384 --state border={} {} {}'.format(border, tapfile, z80file))
     self.assertEqual(error, '')
     with open(z80file, 'rb') as f:
         z80_header = f.read(13)
     self.assertEqual((z80_header[12] // 2) & 7, border)
Example #25
0
 def test_state_im(self):
     block = create_tap_data_block([0])
     tapfile = self._write_tap([block])
     z80file = self.write_bin_file(suffix='.z80')
     im_value = 2
     output, error = self.run_tap2sna('--force --ram load=1,16384 --state im={} {} {}'.format(im_value, tapfile, z80file))
     self.assertEqual(error, '')
     with open(z80file, 'rb') as f:
         z80_header = f.read(30)
     self.assertEqual(z80_header[29] & 3, im_value)
Example #26
0
 def test_option_d(self):
     odir = 'tap2sna-{}'.format(os.getpid())
     self.tempdirs.append(odir)
     block = create_tap_data_block([0])
     tapfile = self._write_tap([block])
     z80_fname = 'test.z80'
     for option in ('-d', '--output-dir'):
         output, error = self.run_tap2sna('{} {} {} {}'.format(option, odir, tapfile, z80_fname))
         self.assertEqual(len(error), 0)
         self.assertTrue(os.path.isfile(os.path.join(odir, z80_fname)))
Example #27
0
 def test_option_u(self, mock_urlopen):
     mock_urlopen.return_value = BytesIO(bytes(create_tap_data_block([1])))
     url = 'http://example.com/test.tap'
     for option, user_agent in (('-u', 'Wget/1.18'), ('--user-agent', 'SkoolKit/6.3')):
         output, error = self.run_tap2sna('{} {} --ram load=1,23296 {} {}/test.z80'.format(option, user_agent, url, self.make_directory()))
         self.assertTrue(output.startswith('Downloading {}\n'.format(url)))
         self.assertEqual(error, '')
         request = mock_urlopen.call_args[0][0]
         self.assertEqual({'User-agent': user_agent}, request.headers)
         self.assertEqual(snapshot[23296], 1)
         mock_urlopen.return_value.seek(0)
Example #28
0
 def test_state_iff(self):
     block = create_tap_data_block([0])
     tapfile = self._write_tap([block])
     z80file = self.write_bin_file(suffix='.z80')
     iff_value = 0
     output, error = self.run_tap2sna('--force --ram load=1,16384 --state iff={} {} {}'.format(iff_value, tapfile, z80file))
     self.assertEqual(error, '')
     with open(z80file, 'rb') as f:
         z80_header = bytearray(f.read(29))
     self.assertEqual(z80_header[27], iff_value)
     self.assertEqual(z80_header[28], iff_value)
Example #29
0
    def test_option_s(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        start = 40000

        output, error = self.run_tap2sna('-f -s {} {} {}'.format(start, tapfile, z80file))
        self.assertEqual(error, '')
        with open(z80file, 'rb') as f:
            z80_header = bytearray(f.read(34))
        self.assertEqual(z80_header[32] + 256 * z80_header[33], start)
Example #30
0
    def test_option_p(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        stack = 32768

        output, error = self.run_tap2sna('-f -p {} {} {}'.format(stack, tapfile, z80file))
        self.assertEqual(error, '')
        with open(z80file, 'rb') as f:
            z80_header = f.read(10)
        self.assertEqual(z80_header[8] + 256 * z80_header[9], stack)
Example #31
0
    def test_option_s(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        start = 40000

        output, error = self.run_tap2sna('-f -s {} {} {}'.format(start, tapfile, z80file))
        self.assertEqual(error, '')
        with open(z80file, 'rb') as f:
            z80_header = f.read(34)
        self.assertEqual(z80_header[32] + 256 * z80_header[33], start)
Example #32
0
 def test_option_u(self, mock_urlopen):
     mock_urlopen.return_value = BytesIO(bytes(create_tap_data_block([1])))
     url = 'http://example.com/test.tap'
     for option, user_agent in (('-u', 'Wget/1.18'), ('--user-agent', 'SkoolKit/6.3')):
         output, error = self.run_tap2sna('{} {} --ram load=1,23296 {} test.z80'.format(option, user_agent, url))
         self.assertTrue(output.startswith('Downloading {}\n'.format(url)))
         self.assertEqual(error, '')
         request = mock_urlopen.call_args[0][0]
         self.assertEqual({'User-agent': user_agent}, request.headers)
         self.assertEqual(snapshot[23296], 1)
         mock_urlopen.return_value.seek(0)
Example #33
0
    def test_option_p(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        stack = 32768

        output, error = self.run_tap2sna('-f -p {} {} {}'.format(stack, tapfile, z80file))
        self.assertEqual(error, '')
        with open(z80file, 'rb') as f:
            z80_header = bytearray(f.read(10))
        self.assertEqual(z80_header[8] + 256 * z80_header[9], stack)
Example #34
0
 def test_state_iff(self):
     block = create_tap_data_block([0])
     tapfile = self._write_tap([block])
     z80file = self.write_bin_file(suffix='.z80')
     iff_value = 0
     output, error = self.run_tap2sna('--force --ram load=1,16384 --state iff={} {} {}'.format(iff_value, tapfile, z80file))
     self.assertEqual(error, '')
     with open(z80file, 'rb') as f:
         z80_header = f.read(29)
     self.assertEqual(z80_header[27], iff_value)
     self.assertEqual(z80_header[28], iff_value)
Example #35
0
 def test_tap_file_in_zip_archive(self):
     data = [1]
     block = create_tap_data_block(data)
     tap_name = 'game.tap'
     zip_fname = self._write_tap([block], zip_archive=True, tap_name=tap_name)
     z80file = self.write_bin_file(suffix='.z80')
     start = 16385
     output, error = self.run_tap2sna('--force --ram load=1,{} {} {}'.format(start, zip_fname, z80file))
     self.assertEqual(output, 'Extracting {}\nWriting {}\n'.format(tap_name, z80file))
     self.assertEqual(error, '')
     snapshot = get_snapshot(z80file)
     self.assertEqual(data, snapshot[start:start + len(data)])
Example #36
0
    def test_standard_load_with_unknown_block_type(self):
        block_type = 1 # Array of numbers
        blocks = [
            create_tap_header_block(data_type=block_type),
            create_tap_data_block([1])
        ]

        tapfile = self._write_tap(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        with self.assertRaises(SkoolKitError) as cm:
            self.run_tap2sna('--force {} {}'.format(tapfile, z80file))
        self.assertEqual(cm.exception.args[0], 'Error while getting snapshot {}: Unknown block type ({}) in header block 1'.format(z80file, block_type))
Example #37
0
 def test_tap_file_in_zip_archive(self):
     data = [1]
     block = create_tap_data_block(data)
     tap_name = 'game.tap'
     zip_fname = self._write_tap([block], zip_archive=True, tap_name=tap_name)
     z80file = self.write_bin_file(suffix='.z80')
     start = 16385
     output, error = self.run_tap2sna('--force --ram load=1,{} {} {}'.format(start, zip_fname, z80file))
     self.assertEqual(output, 'Extracting {}\nWriting {}\n'.format(tap_name, z80file))
     self.assertEqual(error, '')
     snapshot = get_snapshot(z80file)
     self.assertEqual(data, snapshot[start:start + len(data)])
Example #38
0
 def test_tap_file(self):
     data = [1, 2, 4]
     tap_data = create_tap_header_block('test_tap', 32768, len(data))
     tap_data.extend(create_tap_data_block(data))
     tap_data.extend(create_tap_header_block('numbers', data_type=1))
     tap_data.extend(create_tap_data_block([8, 16, 32]))
     tapfile = self.write_bin_file(tap_data, suffix='.tap')
     output, error = self.run_tapinfo(tapfile)
     self.assertEqual(len(error), 0)
     exp_output = [
         '1:', '  Type: Header block', '  Bytes: test_tap',
         '  CODE: 32768,3', '  Length: 19',
         '  Data: 0, 3, 116, 101, 115, 116, 95 ... 3, 0, 0, 128, 0, 0, 172',
         '2:', '  Type: Data block', '  Length: 5',
         '  Data: 255, 1, 2, 4, 7', '3:', '  Type: Header block',
         '  Number array: numbers', '  Length: 19',
         '  Data: 0, 1, 110, 117, 109, 98, 101 ... 0, 0, 0, 0, 0, 0, 81',
         '4:', '  Type: Data block', '  Length: 5',
         '  Data: 255, 8, 16, 32, 56'
     ]
     self.assertEqual(exp_output, output)
Example #39
0
    def test_standard_load_with_unknown_block_type(self):
        block_type = 1 # Array of numbers
        blocks = [
            create_tap_header_block(data_type=block_type),
            create_tap_data_block([1])
        ]

        tapfile = self._write_tap(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        with self.assertRaises(SkoolKitError) as cm:
            self.run_tap2sna('--force {} {}'.format(tapfile, z80file))
        self.assertEqual(cm.exception.args[0], 'Error while getting snapshot {}: Unknown block type ({}) in header block 1'.format(z80file, block_type))
Example #40
0
 def test_default_state(self):
     block = create_tap_data_block([0])
     tapfile = self._write_tap([block])
     z80file = self.write_bin_file(suffix='.z80')
     output, error = self.run_tap2sna('--force --ram load=1,16384 {} {}'.format(tapfile, z80file))
     self.assertEqual(error, '')
     with open(z80file, 'rb') as f:
         z80_header = bytearray(f.read(30))
     self.assertEqual(z80_header[12] & 14, 0) # border=0
     self.assertEqual(z80_header[27], 1) # iff1=1
     self.assertEqual(z80_header[28], 1) # iff2=1
     self.assertEqual(z80_header[29] & 3, 1) # im=1
Example #41
0
 def test_default_state(self):
     block = create_tap_data_block([0])
     tapfile = self._write_tap([block])
     z80file = self.write_bin_file(suffix='.z80')
     output, error = self.run_tap2sna('--force --ram load=1,16384 {} {}'.format(tapfile, z80file))
     self.assertEqual(error, '')
     with open(z80file, 'rb') as f:
         z80_header = f.read(30)
     self.assertEqual(z80_header[12] & 14, 0) # border=0
     self.assertEqual(z80_header[27], 1) # iff1=1
     self.assertEqual(z80_header[28], 1) # iff2=1
     self.assertEqual(z80_header[29] & 3, 1) # im=1
Example #42
0
 def test_option_B_tap_with_hex_address(self):
     prefix = [4] * 4
     address = 23755 - len(prefix)
     prog = [9] * 9
     data = prefix + prog
     tap_data = create_tap_data_block(data)
     tapfile = self.write_bin_file(tap_data, suffix='.tap')
     exp_snapshot = [0] * address + data
     output, error = self.run_tapinfo('-B 1,0x{:04x} {}'.format(address, tapfile))
     self.assertEqual(error, '')
     self.assertEqual(output, 'BASIC DONE!\n')
     self.assertEqual(exp_snapshot, mock_basic_lister.snapshot)
Example #43
0
 def _get_snapshot(self, start=16384, data=None, options='', load_options=None, blocks=None, tzx=False):
     if blocks is None:
         blocks = [create_tap_data_block(data)]
     if tzx:
         tape_file = self._write_tzx(blocks)
     else:
         tape_file = self._write_tap(blocks)
     z80file = self.write_bin_file(suffix='.z80')
     if load_options is None:
         load_options = '--ram load=1,{}'.format(start)
     output, error = self.run_tap2sna('--force {} {} {} {}'.format(load_options, options, tape_file, z80file))
     self.assertEqual(output, 'Writing {}\n'.format(z80file))
     self.assertEqual(error, '')
     return get_snapshot(z80file)
Example #44
0
 def _get_snapshot(self, start=16384, data=None, options='', load_options=None, blocks=None, tzx=False):
     if blocks is None:
         blocks = [create_tap_data_block(data)]
     if tzx:
         tape_file = self._write_tzx(blocks)
     else:
         tape_file = self._write_tap(blocks)
     z80file = self.write_bin_file(suffix='.z80')
     if load_options is None:
         load_options = '--ram load=1,{}'.format(start)
     output, error = self.run_tap2sna('--force {} {} {} {}'.format(load_options, options, tape_file, z80file))
     self.assertEqual(output, 'Writing {}\n'.format(z80file))
     self.assertEqual(error, '')
     return get_snapshot(z80file)
Example #45
0
    def test_standard_load_ignores_truncated_header_block(self):
        code_start = 30000
        code = [2, 3, 4]
        length = len(code)
        blocks = [
            create_tap_header_block(start=code_start)[:-1],
            create_tap_data_block(code),
        ]

        tapfile = self._write_tap(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        output, error = self.run_tap2sna('--force {} {}'.format(tapfile, z80file))
        self.assertEqual(error, '')
        snapshot = get_snapshot(z80file)
        self.assertEqual([0] * length, snapshot[code_start:code_start + length])
Example #46
0
 def test_option_d_with_tap_file(self):
     data = [1, 2, 4, 8]
     tap_data = create_tap_header_block('test_tap02', 49152, len(data))
     tap_data.extend(create_tap_data_block(data))
     tap_data.extend(create_tap_header_block('characters', data_type=2))
     tap_data.extend(create_tap_data_block(list(range(32, 94))))
     tapfile = self.write_bin_file(tap_data, suffix='.tap')
     output, error = self.run_tapinfo('-d {}'.format(tapfile))
     self.assertEqual(error, '')
     exp_output = """
         1:
           Type: Header block
           Bytes: test_tap02
           CODE: 49152,4
           Length: 19
           0000  00 03 74 65 73 74 5F 74 61 70 30 32 04 00 00 C0  ..test_tap02....
           0010  00 00 E9                                         ...
         2:
           Type: Data block
           Length: 6
           0000  FF 01 02 04 08 0F                                ......
         3:
           Type: Header block
           Character array: characters
           Length: 19
           0000  00 02 63 68 61 72 61 63 74 65 72 73 00 00 00 00  ..characters....
           0010  00 00 08                                         ...
         4:
           Type: Data block
           Length: 64
           0000  FF 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E  . !"#$%&'()*+,-.
           0010  2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E  /0123456789:;<=>
           0020  3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E  ?@ABCDEFGHIJKLMN
           0030  4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 01  OPQRSTUVWXYZ[\].
     """
     self.assertEqual(dedent(exp_output).lstrip(), output)
Example #47
0
    def test_standard_load_ignores_truncated_header_block(self):
        code_start = 30000
        code = [2, 3, 4]
        length = len(code)
        blocks = [
            create_tap_header_block(start=code_start)[:-1],
            create_tap_data_block(code),
        ]

        tapfile = self._write_tap(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        output, error = self.run_tap2sna('--force {} {}'.format(tapfile, z80file))
        self.assertEqual(error, '')
        snapshot = get_snapshot(z80file)
        self.assertEqual([0] * length, snapshot[code_start:code_start + length])
Example #48
0
    def test_default_register_values(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        exp_reg_values = {
            'a': 0, 'f': 0, 'bc': 0, 'de': 0, 'hl': 0, 'i': 63, 'r': 0,
            '^bc': 0, '^de': 0, '^hl': 0, 'ix': 0, 'iy': 23610, 'sp': 0, 'pc': 0
        }

        output, error = self.run_tap2sna('--force --ram load=1,16384 {} {}'.format(tapfile, z80file))
        self.assertEqual(error, '')
        with open(z80file, 'rb') as f:
            z80_header = f.read(34)
        for reg, exp_value in exp_reg_values.items():
            offset = Z80_REGISTERS[reg]
            size = len(reg) - 1 if reg.startswith('^') else len(reg)
            if size == 1:
                value = z80_header[offset]
            else:
                value = z80_header[offset] + 256 * z80_header[offset + 1]
            self.assertEqual(value, exp_value)
Example #49
0
class Tap2SnaTest(SkoolKitTestCase):
    def _write_tap(self, blocks, zip_archive=False, tap_name=None):
        tap_data = []
        for block in blocks:
            tap_data.extend(block)
        if zip_archive:
            archive_fname = self.write_bin_file(suffix='.zip')
            with ZipFile(archive_fname, 'w') as archive:
                archive.writestr(tap_name or 'game.tap', bytearray(tap_data))
            return archive_fname
        return self.write_bin_file(tap_data, suffix='.tap')

    def _write_tzx(self, blocks):
        tzx_data = [ord(c) for c in "ZXTape!"]
        tzx_data.extend((26, 1, 20))
        for block in blocks:
            tzx_data.extend(block)
        return self.write_bin_file(tzx_data, suffix='.tzx')

    def _get_snapshot(self,
                      start=16384,
                      data=None,
                      options='',
                      load_options=None,
                      blocks=None,
                      tzx=False):
        if blocks is None:
            blocks = [create_tap_data_block(data)]
        if tzx:
            tape_file = self._write_tzx(blocks)
        else:
            tape_file = self._write_tap(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        if load_options is None:
            load_options = '--ram load=1,{}'.format(start)
        output, error = self.run_tap2sna('--force {} {} {} {}'.format(
            load_options, options, tape_file, z80file))
        self.assertEqual(output, 'Writing {}\n'.format(z80file))
        self.assertEqual(error, '')
        return get_snapshot(z80file)

    def _test_bad_spec(self, option, exp_error):
        odir = self.make_directory()
        tapfile = self._write_tap([create_tap_data_block([1])])
        z80fname = 'test.z80'
        with self.assertRaises(SkoolKitError) as cm:
            self.run_tap2sna('--ram load=1,16384 {} -d {} {} {}'.format(
                option, odir, tapfile, z80fname))
        self.assertEqual(
            cm.exception.args[0],
            'Error while getting snapshot {}: {}'.format(z80fname, exp_error))

    @patch.object(tap2sna, 'make_z80', mock_make_z80)
    def test_default_option_values(self):
        self.run_tap2sna('in.tap {}/out.z80'.format(self.make_directory()))
        options = make_z80_args[1]
        self.assertIsNone(options.output_dir)
        self.assertFalse(options.force)
        self.assertIsNone(options.stack)
        self.assertEqual([], options.ram_ops)
        self.assertEqual([], options.reg)
        self.assertIsNone(options.start)
        self.assertEqual([], options.state)
        self.assertEqual(options.user_agent, '')

    def test_no_arguments(self):
        output, error = self.run_tap2sna(catch_exit=2)
        self.assertEqual(output, '')
        self.assertTrue(error.startswith('usage:'))

    def test_invalid_arguments(self):
        for args in ('--foo', '-k test.zip'):
            output, error = self.run_tap2sna(args, catch_exit=2)
            self.assertEqual(output, '')
            self.assertTrue(error.startswith('usage:'))

    def test_option_d(self):
        odir = '{}/tap2sna'.format(self.make_directory())
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80_fname = 'test.z80'
        for option in ('-d', '--output-dir'):
            output, error = self.run_tap2sna('{} {} {} {}'.format(
                option, odir, tapfile, z80_fname))
            self.assertEqual(len(error), 0)
            self.assertTrue(os.path.isfile(os.path.join(odir, z80_fname)))

    @patch.object(tap2sna, 'make_z80', mock_make_z80)
    def test_options_p_stack(self):
        for option, stack in (('-p', 24576), ('--stack', 49152)):
            output, error = self.run_tap2sna('{} {} in.tap {}/out.z80'.format(
                option, stack, self.make_directory()))
            self.assertEqual(output, '')
            self.assertEqual(error, '')
            url, options, z80 = make_z80_args
            self.assertEqual(['sp={}'.format(stack)], options.reg)

    @patch.object(tap2sna, 'make_z80', mock_make_z80)
    def test_options_p_stack_with_hex_address(self):
        for option, stack in (('-p', '0x6ff0'), ('--stack', '0x9ABC')):
            output, error = self.run_tap2sna('{} {} in.tap {}/out.z80'.format(
                option, stack, self.make_directory()))
            self.assertEqual(output, '')
            self.assertEqual(error, '')
            url, options, z80 = make_z80_args
            self.assertEqual(['sp={}'.format(int(stack[2:], 16))], options.reg)

    def test_option_p(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        stack = 32768

        output, error = self.run_tap2sna('-f -p {} {} {}'.format(
            stack, tapfile, z80file))
        self.assertEqual(error, '')
        with open(z80file, 'rb') as f:
            z80_header = f.read(10)
        self.assertEqual(z80_header[8] + 256 * z80_header[9], stack)

    @patch.object(tap2sna, 'make_z80', mock_make_z80)
    def test_options_s_start(self):
        start = 30000
        exp_reg = ['pc={}'.format(start)]
        for option in ('-s', '--start'):
            output, error = self.run_tap2sna('{} {} in.tap {}/out.z80'.format(
                option, start, self.make_directory()))
            self.assertEqual(output, '')
            self.assertEqual(error, '')
            url, options, z80 = make_z80_args
            self.assertEqual(exp_reg, options.reg)

    @patch.object(tap2sna, 'make_z80', mock_make_z80)
    def test_options_s_start_with_hex_address(self):
        start = 30000
        exp_reg = ['pc={}'.format(start)]
        for option in ('-s', '--start'):
            output, error = self.run_tap2sna(
                '{} 0x{:04X} in.tap {}/out.z80'.format(option, start,
                                                       self.make_directory()))
            self.assertEqual(output, '')
            self.assertEqual(error, '')
            url, options, z80 = make_z80_args
            self.assertEqual(exp_reg, options.reg)

    def test_option_s(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        start = 40000

        output, error = self.run_tap2sna('-f -s {} {} {}'.format(
            start, tapfile, z80file))
        self.assertEqual(error, '')
        with open(z80file, 'rb') as f:
            z80_header = f.read(34)
        self.assertEqual(z80_header[32] + 256 * z80_header[33], start)

    @patch.object(tap2sna, '_write_z80', mock_write_z80)
    @patch.object(tap2sna, 'urlopen')
    def test_option_u(self, mock_urlopen):
        mock_urlopen.return_value = BytesIO(bytes(create_tap_data_block([1])))
        url = 'http://example.com/test.tap'
        for option, user_agent in (('-u', 'Wget/1.18'), ('--user-agent',
                                                         'SkoolKit/6.3')):
            output, error = self.run_tap2sna(
                '{} {} --ram load=1,23296 {} {}/test.z80'.format(
                    option, user_agent, url, self.make_directory()))
            self.assertTrue(output.startswith('Downloading {}\n'.format(url)))
            self.assertEqual(error, '')
            request = mock_urlopen.call_args[0][0]
            self.assertEqual({'User-agent': user_agent}, request.headers)
            self.assertEqual(snapshot[23296], 1)
            mock_urlopen.return_value.seek(0)

    def test_option_V(self):
        for option in ('-V', '--version'):
            output, error = self.run_tap2sna(option, catch_exit=0)
            self.assertEqual(output, 'SkoolKit {}\n'.format(VERSION))

    def test_nonexistent_tap_file(self):
        odir = self.make_directory()
        tap_fname = '{}/test.tap'.format(odir)
        z80_fname = 'test.z80'
        with self.assertRaises(SkoolKitError) as cm:
            self.run_tap2sna('{} {}/{}'.format(tap_fname, odir, z80_fname))
        self.assertEqual(
            cm.exception.args[0],
            'Error while getting snapshot {}: {}: file not found'.format(
                z80_fname, tap_fname))

    def test_load_nonexistent_block(self):
        tapfile = self._write_tap([create_tap_data_block([1])])
        block_num = 2
        with self.assertRaises(SkoolKitError) as cm:
            self.run_tap2sna('--ram load={},16384 {} {}/test.z80'.format(
                block_num, tapfile, self.make_directory()))
        self.assertEqual(
            cm.exception.args[0],
            'Error while getting snapshot test.z80: Block {} not found'.format(
                block_num))

    def test_zip_archive_with_no_tape_file(self):
        archive_fname = self.write_bin_file(suffix='.zip')
        with ZipFile(archive_fname, 'w') as archive:
            archive.writestr('game.txt', bytearray((1, 2)))
        z80_fname = 'test.z80'
        with self.assertRaises(SkoolKitError) as cm:
            self.run_tap2sna('{} {}/{}'.format(archive_fname,
                                               self.make_directory(),
                                               z80_fname))
        self.assertEqual(
            cm.exception.args[0],
            'Error while getting snapshot {}: No TAP or TZX file found'.format(
                z80_fname))

    def test_standard_load_from_tap_file(self):
        basic_data = [1, 2, 3]
        code_start = 32768
        code = [4, 5]
        blocks = [
            create_tap_header_block(data_type=0),
            create_tap_data_block(basic_data),
            create_tap_header_block(start=code_start),
            create_tap_data_block(code)
        ]

        tapfile = self._write_tap(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        output, error = self.run_tap2sna('--force {} {}'.format(
            tapfile, z80file))
        self.assertEqual(error, '')
        snapshot = get_snapshot(z80file)
        self.assertEqual(basic_data, snapshot[23755:23755 + len(basic_data)])
        self.assertEqual(code, snapshot[code_start:code_start + len(code)])

    def test_standard_load_ignores_headerless_block(self):
        code_start = 16384
        code = [2]
        blocks = [
            create_tap_header_block(start=code_start),
            create_tap_data_block(code),
            create_tap_data_block([23])
        ]

        tapfile = self._write_tap(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        output, error = self.run_tap2sna('--force {} {}'.format(
            tapfile, z80file))
        self.assertEqual(error, '')
        snapshot = get_snapshot(z80file)
        self.assertEqual(code, snapshot[code_start:code_start + len(code)])

    def test_standard_load_ignores_truncated_header_block(self):
        code_start = 30000
        code = [2, 3, 4]
        length = len(code)
        blocks = [
            create_tap_header_block(start=code_start)[:-1],
            create_tap_data_block(code),
        ]

        tapfile = self._write_tap(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        output, error = self.run_tap2sna('--force {} {}'.format(
            tapfile, z80file))
        self.assertEqual(error, '')
        snapshot = get_snapshot(z80file)
        self.assertEqual([0] * length,
                         snapshot[code_start:code_start + length])

    def test_standard_load_with_unknown_block_type(self):
        block_type = 1  # Array of numbers
        blocks = [
            create_tap_header_block(data_type=block_type),
            create_tap_data_block([1])
        ]

        tapfile = self._write_tap(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        with self.assertRaises(SkoolKitError) as cm:
            self.run_tap2sna('--force {} {}'.format(tapfile, z80file))
        self.assertEqual(
            cm.exception.args[0],
            'Error while getting snapshot {}: Unknown block type ({}) in header block 1'
            .format(z80file, block_type))

    def test_standard_load_from_tzx_file(self):
        basic_data = [6, 7]
        code_start = 49152
        code = [8, 9, 10]
        blocks = [
            [48, 3, 65, 66, 67],  # Text description block (0x30): ABC
            create_tzx_header_block(data_type=0),
            create_tzx_data_block(basic_data),
            create_tzx_header_block(start=code_start),
            create_tzx_data_block(code)
        ]

        tzxfile = self._write_tzx(blocks)
        z80file = self.write_bin_file(suffix='.z80')
        output, error = self.run_tap2sna('--force {} {}'.format(
            tzxfile, z80file))
        self.assertEqual(error, '')
        snapshot = get_snapshot(z80file)
        self.assertEqual(basic_data, snapshot[23755:23755 + len(basic_data)])
        self.assertEqual(code, snapshot[code_start:code_start + len(code)])

    def test_ram_load(self):
        start = 16384
        data = [237, 1, 1, 1, 1, 1]
        snapshot = self._get_snapshot(start, data)
        self.assertEqual(data, snapshot[start:start + len(data)])

    def test_ram_load_with_length(self):
        start = 16384
        data = [1, 2, 3, 4]
        length = 2
        snapshot = self._get_snapshot(start,
                                      data,
                                      load_options='--ram load=1,{},{}'.format(
                                          start, length))
        self.assertEqual(data[:length], snapshot[start:start + length])
        self.assertEqual([0] * (len(data) - length),
                         snapshot[start + length:start + len(data)])

    def test_ram_load_with_step(self):
        start = 16385
        data = [5, 4, 3]
        step = 2
        snapshot = self._get_snapshot(
            start,
            data,
            load_options='--ram load=1,{},,{}'.format(start, step))
        self.assertEqual(data, snapshot[start:start + len(data) * step:step])

    def test_ram_load_with_offset(self):
        start = 16384
        data = [15, 16, 17]
        offset = 5
        snapshot = self._get_snapshot(
            start,
            data,
            load_options='--ram load=1,{},,,{}'.format(start, offset))
        self.assertEqual(data,
                         snapshot[start + offset:start + offset + len(data)])

    def test_ram_load_with_increment(self):
        start = 65534
        data = [8, 9, 10]
        inc = 65533
        snapshot = self._get_snapshot(
            start,
            data,
            load_options='--ram load=1,{},,,,{}'.format(start, inc))
        self.assertEqual([data[2]] + data[:2], snapshot[65533:])

    def test_ram_load_wraparound_with_step(self):
        start = 65535
        data = [23, 24, 25]
        step = 8193
        snapshot = self._get_snapshot(
            start,
            data,
            load_options='--ram load=1,{},,{}'.format(start, step))
        self.assertEqual(snapshot[start], data[0])
        self.assertEqual(snapshot[(start + 2 * step) & 65535], data[2])

    def test_ram_load_with_hexadecimal_parameters(self):
        start = 30000
        data = [1, 2, 3]
        step = 2
        offset = 3
        inc = 0
        snapshot = self._get_snapshot(
            start,
            data,
            load_options=
            '--ram load=1,0x{:04x},0x{:04x},0x{:04x},0x{:04x},0x{:04x}'.format(
                start, len(data), step, offset, inc))
        self.assertEqual(data, snapshot[30003:30008:2])

    def test_ram_load_bad_address(self):
        self._test_bad_spec('--ram load=1,abcde',
                            'Invalid integer in load spec: 1,abcde')

    def test_ram_poke_single_address(self):
        start = 16384
        data = [4, 5, 6]
        poke_addr = 16386
        poke_val = 255
        snapshot = self._get_snapshot(
            start, data, '--ram poke={},{}'.format(poke_addr, poke_val))
        self.assertEqual(data[:2], snapshot[start:start + 2])
        self.assertEqual(snapshot[poke_addr], poke_val)

    def test_ram_poke_address_range(self):
        start = 16384
        data = [1, 1, 1]
        poke_addr_start = 16384
        poke_addr_end = 16383 + len(data)
        poke_val = 254
        snapshot = self._get_snapshot(
            start, data, '--ram poke={}-{},{}'.format(poke_addr_start,
                                                      poke_addr_end, poke_val))
        self.assertEqual([poke_val] * len(data),
                         snapshot[poke_addr_start:poke_addr_end + 1])

    def test_ram_poke_address_range_with_xor(self):
        start = 30000
        data = [1, 2, 3]
        end = start + len(data) - 1
        xor_val = 129
        snapshot = self._get_snapshot(
            start, data, '--ram poke={}-{},^{}'.format(start, end, xor_val))
        exp_data = [b ^ xor_val for b in data]
        self.assertEqual(exp_data, snapshot[start:end + 1])

    def test_ram_poke_address_range_with_add(self):
        start = 40000
        data = [100, 200, 32]
        end = start + len(data) - 1
        add_val = 130
        snapshot = self._get_snapshot(
            start, data, '--ram poke={}-{},+{}'.format(start, end, add_val))
        exp_data = [(b + add_val) & 255 for b in data]
        self.assertEqual(exp_data, snapshot[start:end + 1])

    def test_ram_poke_address_range_with_step(self):
        snapshot = self._get_snapshot(16384, [2, 9, 2],
                                      '--ram poke=16384-16386-2,253')
        self.assertEqual([253, 9, 253], snapshot[16384:16387])

    def test_ram_poke_hex_address(self):
        address, value = 16385, 253
        snapshot = self._get_snapshot(
            16384, [1], '--ram poke=${:X},{}'.format(address, value))
        self.assertEqual(snapshot[address], value)

    def test_ram_poke_0x_hex_values(self):
        snapshot = self._get_snapshot(16384, [2, 1, 2],
                                      '--ram poke=0x4000-0x4002-0x02,0x2a')
        self.assertEqual([42, 1, 42], snapshot[16384:16387])

    def test_ram_poke_bad_value(self):
        self._test_bad_spec('--ram poke=1', 'Value missing in poke spec: 1')
        self._test_bad_spec('--ram poke=q', 'Value missing in poke spec: q')
        self._test_bad_spec('--ram poke=1,x',
                            'Invalid value in poke spec: 1,x')
        self._test_bad_spec('--ram poke=x,1',
                            'Invalid address range in poke spec: x,1')
        self._test_bad_spec('--ram poke=1-y,1',
                            'Invalid address range in poke spec: 1-y,1')
        self._test_bad_spec('--ram poke=1-3-z,1',
                            'Invalid address range in poke spec: 1-3-z,1')

    def test_ram_move(self):
        start = 16384
        data = [5, 6, 7]
        src = start
        size = len(data)
        dest = 16387
        snapshot = self._get_snapshot(
            start, data, '--ram move={},{},{}'.format(src, size, dest))
        self.assertEqual(data, snapshot[start:start + len(data)])
        self.assertEqual(data, snapshot[dest:dest + len(data)])

    def test_ram_move_hex_address(self):
        src, size, dest = 16384, 1, 16385
        value = 3
        snapshot = self._get_snapshot(
            src, [value], '--ram move=${:X},{},${:x}'.format(src, size, dest))
        self.assertEqual(snapshot[dest], value)

    def test_ram_move_0x_hex_values(self):
        src, size, dest = 16385, 1, 16384
        value = 2
        snapshot = self._get_snapshot(
            src, [value],
            '--ram move=0x{:X},0x{:X},0x{:x}'.format(src, size, dest))
        self.assertEqual(snapshot[dest], value)

    def test_ram_move_bad_address(self):
        self._test_bad_spec(
            '--ram move=1',
            'Not enough arguments in move spec (expected 3): 1')
        self._test_bad_spec(
            '--ram move=1,2',
            'Not enough arguments in move spec (expected 3): 1,2')
        self._test_bad_spec('--ram move=x,2,3',
                            'Invalid integer in move spec: x,2,3')
        self._test_bad_spec('--ram move=1,y,3',
                            'Invalid integer in move spec: 1,y,3')
        self._test_bad_spec('--ram move=1,2,z',
                            'Invalid integer in move spec: 1,2,z')

    def test_ram_invalid_operation(self):
        self._test_bad_spec('--ram foo=bar', 'Invalid operation: foo=bar')

    def test_ram_help(self):
        output, error = self.run_tap2sna('--ram help')
        self.assertTrue(
            output.startswith(
                'Usage: --ram load=block,start[,length,step,offset,inc]\n'))
        self.assertEqual(error, '')

    def test_tap_file_in_zip_archive(self):
        data = [1]
        block = create_tap_data_block(data)
        tap_name = 'game.tap'
        zip_fname = self._write_tap([block],
                                    zip_archive=True,
                                    tap_name=tap_name)
        z80file = self.write_bin_file(suffix='.z80')
        start = 16385
        output, error = self.run_tap2sna(
            '--force --ram load=1,{} {} {}'.format(start, zip_fname, z80file))
        self.assertEqual(
            output, 'Extracting {}\nWriting {}\n'.format(tap_name, z80file))
        self.assertEqual(error, '')
        snapshot = get_snapshot(z80file)
        self.assertEqual(data, snapshot[start:start + len(data)])

    def test_invalid_tzx_file(self):
        tzxfile = self.write_bin_file([1, 2, 3], suffix='.tzx')
        z80file = 'test.z80'
        with self.assertRaises(SkoolKitError) as cm:
            self.run_tap2sna('{} {}/{}'.format(tzxfile, self.make_directory(),
                                               z80file))
        self.assertEqual(
            cm.exception.args[0],
            'Error while getting snapshot {}: Not a TZX file'.format(z80file))

    def test_tzx_block_type_0x10(self):
        data = [1, 2, 4]
        start = 16386
        block = create_tzx_data_block(data)
        snapshot = self._get_snapshot(start, blocks=[block], tzx=True)
        self.assertEqual(data, snapshot[start:start + len(data)])

    def test_tzx_block_type_0x11(self):
        data = [2, 3, 5]
        block = [17]  # Block ID
        block.extend([0] * 15)
        data_block = create_data_block(data)
        length = len(data_block)
        block.extend((length % 256, length // 256, 0))
        block.extend(data_block)
        start = 16387
        snapshot = self._get_snapshot(start, blocks=[block], tzx=True)
        self.assertEqual(data, snapshot[start:start + len(data)])

    def test_tzx_block_type_0x14(self):
        data = [7, 11, 13]
        block = [20]  # Block ID
        block.extend([0] * 7)
        data_block = create_data_block(data)
        length = len(data_block)
        block.extend((length % 256, length // 256, 0))
        block.extend(data_block)
        start = 16388
        snapshot = self._get_snapshot(start, blocks=[block], tzx=True)
        self.assertEqual(data, snapshot[start:start + len(data)])

    def test_load_first_byte_of_block(self):
        data = [1, 2, 3, 4, 5]
        block = [20]  # Block ID
        block.extend([0] * 7)
        length = len(data)
        block.extend((length % 256, length // 256, 0))
        block.extend(data)
        start = 16389
        load_options = '--ram load=+1,{}'.format(start)
        snapshot = self._get_snapshot(load_options=load_options,
                                      blocks=[block],
                                      tzx=True)
        exp_data = data[:-1]
        self.assertEqual(exp_data, snapshot[start:start + len(exp_data)])

    def test_load_last_byte_of_block(self):
        data = [1, 2, 3, 4, 5]
        block = [20]  # Block ID
        block.extend([0] * 7)
        length = len(data)
        block.extend((length % 256, length // 256, 0))
        block.extend(data)
        start = 16390
        load_options = '--ram load=1+,{}'.format(start)
        snapshot = self._get_snapshot(load_options=load_options,
                                      blocks=[block],
                                      tzx=True)
        exp_data = data[1:]
        self.assertEqual(exp_data, snapshot[start:start + len(exp_data)])

    def test_load_first_and_last_bytes_of_block(self):
        data = [1, 2, 3, 4, 5]
        block = [20]  # Block ID
        block.extend([0] * 7)
        length = len(data)
        block.extend((length % 256, length // 256, 0))
        block.extend(data)
        start = 16391
        load_options = '--ram load=+1+,{}'.format(start)
        snapshot = self._get_snapshot(load_options=load_options,
                                      blocks=[block],
                                      tzx=True)
        self.assertEqual(data, snapshot[start:start + len(data)])

    def test_tzx_with_unsupported_blocks(self):
        blocks = []
        blocks.append((18, 0, 0, 0, 0))  # 0x12 Pure Tone
        blocks.append((19, 2, 0, 0, 0, 0))  # 0x13 Pulse sequence
        blocks.append([21] + [0] * 5 + [1, 0, 0, 0])  # 0x15 Direct Recording
        blocks.append([24, 11] + [0] * 14)  # 0x18 CSW Recording
        blocks.append([25, 20] + [0] * 23)  # 0x19 Generalized Data Block
        blocks.append(
            (32, 0, 0))  # 0x20 Pause (silence) or 'Stop the Tape' command
        blocks.append((33, 1, 32))  # 0x21 Group start
        blocks.append((34, ))  # 0x22 - Group end
        blocks.append((35, 0, 0))  # 0x23 Jump to block
        blocks.append((36, 2, 0))  # 0x24 Loop start
        blocks.append((37, ))  # 0x25 Loop end
        blocks.append((38, 1, 0, 0, 0))  # 0x26 Call sequence
        blocks.append((39, ))  # 0x27 Return from sequence
        blocks.append((40, 5, 0, 1, 0, 0, 1, 32))  # 0x28 Select block
        blocks.append((42, 0, 0, 0, 0))  # 0x2A Stop the tape if in 48K mode
        blocks.append((43, 1, 0, 0, 0, 1))  # 0x2B Set signal level
        blocks.append((48, 1, 65))  # 0x30 Text description
        blocks.append((49, 0, 1, 66))  # 0x31 Message block
        blocks.append((50, 4, 0, 1, 0, 1, 33))  # 0x32 Archive info
        blocks.append((51, 1, 0, 0, 0))  # 0x33 Hardware type
        blocks.append([53] + [32] * 16 + [1] +
                      [0] * 4)  # 0x35 Custom info block
        blocks.append([90] + [0] * 9)  # 0x5A "Glue" block
        data = [2, 4, 6]
        blocks.append(create_tzx_data_block(data))
        start = 16388
        load_options = '--ram load={},{}'.format(len(blocks), start)
        snapshot = self._get_snapshot(load_options=load_options,
                                      blocks=blocks,
                                      tzx=True)
        self.assertEqual(data, snapshot[start:start + len(data)])

    def test_tzx_with_unknown_block(self):
        block_id = 22
        block = [block_id, 0]
        tzxfile = self._write_tzx([block])
        z80file = 'test.z80'
        with self.assertRaises(SkoolKitError) as cm:
            self.run_tap2sna('{} {}/{}'.format(tzxfile, self.make_directory(),
                                               z80file))
        self.assertEqual(
            cm.exception.args[0],
            'Error while getting snapshot {}: Unknown TZX block ID: 0x{:X}'.
            format(z80file, block_id))

    def test_default_register_values(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        exp_reg_values = {
            'a': 0,
            'f': 0,
            'bc': 0,
            'de': 0,
            'hl': 0,
            'i': 63,
            'r': 0,
            '^bc': 0,
            '^de': 0,
            '^hl': 0,
            'ix': 0,
            'iy': 23610,
            'sp': 0,
            'pc': 0
        }

        output, error = self.run_tap2sna(
            '--force --ram load=1,16384 {} {}'.format(tapfile, z80file))
        self.assertEqual(error, '')
        with open(z80file, 'rb') as f:
            z80_header = f.read(34)
        for reg, exp_value in exp_reg_values.items():
            offset = Z80_REGISTERS[reg]
            size = len(reg) - 1 if reg.startswith('^') else len(reg)
            if size == 1:
                value = z80_header[offset]
            else:
                value = z80_header[offset] + 256 * z80_header[offset + 1]
            self.assertEqual(value, exp_value)

    def test_reg(self):
        block = create_tap_data_block([1])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        reg_dicts = ({
            '^a': 1,
            '^b': 2,
            '^c': 3,
            '^d': 4,
            '^e': 5,
            '^f': 6,
            '^h': 7,
            '^l': 8
        }, {
            'a': 9,
            'b': 10,
            'c': 11,
            'd': 12,
            'e': 13,
            'f': 14,
            'h': 15,
            'l': 16,
            'r': 129
        }, {
            '^bc': 258,
            '^de': 515,
            '^hl': 65534,
            'bc': 259,
            'de': 516,
            'hl': 65533
        }, {
            'i': 13,
            'ix': 1027,
            'iy': 1284,
            'pc': 1541,
            'r': 23,
            'sp': 32769
        })
        for reg_dict in reg_dicts:
            reg_options = ' '.join(
                ['--reg {}={}'.format(r, v) for r, v in reg_dict.items()])
            output, error = self.run_tap2sna(
                '--force --ram load=1,16384 {} {} {}'.format(
                    reg_options, tapfile, z80file))
            self.assertEqual(error, '')
            with open(z80file, 'rb') as f:
                z80_header = f.read(34)
            for reg, exp_value in reg_dict.items():
                offset = Z80_REGISTERS[reg]
                size = len(reg) - 1 if reg.startswith('^') else len(reg)
                if size == 1:
                    value = z80_header[offset]
                else:
                    value = z80_header[offset] + 256 * z80_header[offset + 1]
                self.assertEqual(value, exp_value)
                if reg == 'r' and exp_value & 128:
                    self.assertEqual(z80_header[12] & 1, 1)

    def test_reg_hex_value(self):
        odir = self.make_directory()
        tapfile = self._write_tap([create_tap_data_block([1])])
        z80fname = 'test.z80'
        reg_value = 35487
        output, error = self.run_tap2sna(
            '--ram load=1,16384 --reg bc=${:x} -d {} {} {}'.format(
                reg_value, odir, tapfile, z80fname))
        self.assertEqual(error, '')
        with open(os.path.join(odir, z80fname), 'rb') as f:
            z80_header = f.read(4)
        self.assertEqual(z80_header[2] + 256 * z80_header[3], reg_value)

    def test_reg_0x_hex_value(self):
        odir = self.make_directory()
        tapfile = self._write_tap([create_tap_data_block([1])])
        z80fname = 'test.z80'
        reg_value = 54873
        output, error = self.run_tap2sna(
            '--ram load=1,16384 --reg hl=0x{:x} -d {} {} {}'.format(
                reg_value, odir, tapfile, z80fname))
        self.assertEqual(error, '')
        with open(os.path.join(odir, z80fname), 'rb') as f:
            z80_header = f.read(6)
        self.assertEqual(z80_header[4] + 256 * z80_header[5], reg_value)

    def test_reg_bad_value(self):
        self._test_bad_spec('--reg bc=A2',
                            'Cannot parse register value: bc=A2')

    def test_ram_invalid_register(self):
        self._test_bad_spec('--reg iz=1', 'Invalid register: iz=1')

    def test_reg_help(self):
        output, error = self.run_tap2sna('--reg help')
        self.assertTrue(output.startswith('Usage: --reg name=value\n'))
        self.assertEqual(error, '')

    def test_default_state(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        output, error = self.run_tap2sna(
            '--force --ram load=1,16384 {} {}'.format(tapfile, z80file))
        self.assertEqual(error, '')
        with open(z80file, 'rb') as f:
            z80_header = f.read(30)
        self.assertEqual(z80_header[12] & 14, 0)  # border=0
        self.assertEqual(z80_header[27], 1)  # iff1=1
        self.assertEqual(z80_header[28], 1)  # iff2=1
        self.assertEqual(z80_header[29] & 3, 1)  # im=1

    def test_state_iff(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        iff_value = 0
        output, error = self.run_tap2sna(
            '--force --ram load=1,16384 --state iff={} {} {}'.format(
                iff_value, tapfile, z80file))
        self.assertEqual(error, '')
        with open(z80file, 'rb') as f:
            z80_header = f.read(29)
        self.assertEqual(z80_header[27], iff_value)
        self.assertEqual(z80_header[28], iff_value)

    def test_state_iff_bad_value(self):
        self._test_bad_spec('--state iff=fa', 'Cannot parse integer: iff=fa')

    def test_state_im(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        im_value = 2
        output, error = self.run_tap2sna(
            '--force --ram load=1,16384 --state im={} {} {}'.format(
                im_value, tapfile, z80file))
        self.assertEqual(error, '')
        with open(z80file, 'rb') as f:
            z80_header = f.read(30)
        self.assertEqual(z80_header[29] & 3, im_value)

    def test_state_im_bad_value(self):
        self._test_bad_spec('--state im=Q', 'Cannot parse integer: im=Q')

    def test_state_border(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        border = 4
        output, error = self.run_tap2sna(
            '--force --ram load=1,16384 --state border={} {} {}'.format(
                border, tapfile, z80file))
        self.assertEqual(error, '')
        with open(z80file, 'rb') as f:
            z80_header = f.read(13)
        self.assertEqual((z80_header[12] // 2) & 7, border)

    def test_state_border_bad_value(self):
        self._test_bad_spec('--state border=x!',
                            'Cannot parse integer: border=x!')

    def test_state_invalid_parameter(self):
        self._test_bad_spec('--state baz=2', 'Invalid parameter: baz=2')

    def test_state_help(self):
        output, error = self.run_tap2sna('--state help')
        self.assertTrue(output.startswith('Usage: --state name=value\n'))
        self.assertEqual(error, '')

    def test_args_from_file(self):
        data = [1, 2, 3, 4]
        start = 49152
        args = """
            ; Comment
            # Another comment
            --force ; Overwrite
            --ram load=1,{} # Load first block
        """.format(start)
        args_file = self.write_text_file(textwrap.dedent(args).strip(),
                                         suffix='.t2s')
        snapshot = self._get_snapshot(start, data, '@{}'.format(args_file))
        self.assertEqual(data, snapshot[start:start + len(data)])

    @patch.object(
        tap2sna, 'urlopen',
        Mock(return_value=BytesIO(bytearray(create_tap_data_block([2, 3])))))
    @patch.object(tap2sna, '_write_z80', mock_write_z80)
    def test_remote_download(self):
        data = [2, 3]
        start = 17000
        url = 'http://example.com/test.tap'
        output, error = self.run_tap2sna(
            '--ram load=1,{} {} {}/test.z80'.format(start, url,
                                                    self.make_directory()))
        self.assertTrue(output.startswith('Downloading {}\n'.format(url)))
        self.assertEqual(error, '')
        self.assertEqual(data, snapshot[start:start + len(data)])

    @patch.object(tap2sna, 'urlopen',
                  Mock(side_effect=urllib.error.HTTPError(
                      '', 403, 'Forbidden', None, None)))
    def test_http_error_on_remote_download(self):
        with self.assertRaisesRegex(
                SkoolKitError,
                '^Error while getting snapshot test.z80: HTTP Error 403: Forbidden$'
        ):
            self.run_tap2sna('http://example.com/test.zip {}/test.z80'.format(
                self.make_directory()))

    def test_no_clobber(self):
        block = create_tap_data_block([0])
        tapfile = self._write_tap([block])
        z80file = self.write_bin_file(suffix='.z80')
        output, error = self.run_tap2sna('--ram load=1,16384 {} {}'.format(
            tapfile, z80file))
        self.assertTrue(
            output.startswith(
                '{}: file already exists; use -f to overwrite\n'.format(
                    z80file)))
        self.assertEqual(error, '')
Example #50
0
 def test_load_nonexistent_block(self):
     tapfile = self._write_tap([create_tap_data_block([1])])
     block_num = 2
     with self.assertRaises(SkoolKitError) as cm:
         self.run_tap2sna('--ram load={},16384 {} test.z80'.format(block_num, tapfile))
     self.assertEqual(cm.exception.args[0], 'Error while getting snapshot test.z80: Block {} not found'.format(block_num))