def test_all_bad_name_locations(self): """SSPatcherError is raised when reading from everywhere except the location of the wavetable names. This test is expected to take a few minutes to run since it tries to read from every possible location. """ for i in range(0, sspatcher.IMAGE_SIZE): if i != self.old_name_offset: sspatcher.WT_NAME_OFFSET = i with self.assertRaises( sspatcher.SSPatcherError, msg= 'Read names from location {:X} did not raise an SSPatcherError.' .format(i)): sspatcher.read_wt_names(self.test_image)
def test_success(self): """Verify that a copy of the rom image is patched using test data.""" self.addCleanup(functools.partial(os.remove, self.PATCHED_IMAGE_PATH)) self.addCleanup(functools.partial(shutil.rmtree, TEMP_DIRECTORY)) os.mkdir(TEMP_DIRECTORY) # Generate some fake wavetables using random data for i in range(sspatcher.NUM_WT): with open(os.path.join(TEMP_DIRECTORY, 'wt{}.raw'.format(i)), 'wb') as f: f.write(os.urandom(sspatcher.WT_DATA_LENGTH)) # Make a copy of the test imgae and patch it shutil.copyfile(REAL_TEST_IMAGE_PATH, self.PATCHED_IMAGE_PATH) sspatcher.patch(TEMP_DIRECTORY, self.PATCHED_IMAGE_PATH) # Verify that what we read from the ROM image is the same as what's in the test data. with open(self.PATCHED_IMAGE_PATH, 'rb') as f: names = sspatcher.read_wt_names(f) tables = sspatcher.read_wt_data(f) filenames = { os.path.splitext(name)[0].rjust(6).encode(): name for name in os.listdir(TEMP_DIRECTORY) } for name, table in zip(names, tables): self.assertIn(name, filenames.keys()) with open(os.path.join(TEMP_DIRECTORY, filenames[name]), 'rb') as f: self.assertEqual(table, f.read())
def test_good_name_location(self): """Expected wavetable names are extracted from the factory image.""" # List of factory wavetable names. First copied from the Shapeshifter manual, then adjusted to the names # actually present in the factory image which use a couple different styles of padding with spaces to # make all names exactly 8 characters. factory_names = [ b"Basic1", b"Basic2", b"BasRec", b"BiPuls", b"BitCr1", b"BitCr2", b"BitCr3", b"BitCr4", b"Buzzer", b"Cello1", b"Cello2", b"Chip 1", b"Chip 2", b"Chip 3", b"Chip 4", b"Chip 5", b"Chip 6", b"Chirp1", b"Chirp2", b"Chirp3", b"Chirp4", b"Chirp5", b"Chirp6", b"Chirp7", b"Chirp8", b"Chirp9", b"Chrp10", b"Chrp11", b"Chrp12", b"Chrp13", b"Chrp14", b"Chrp15", b"Chrp16", b"Chrp17", b"Chrp18", b"Chrp19", b"Chrp20", b"Clrnet", b" Clav1", b" Clav2", b"Dstrt1", b"Dstrt2", b"Dstrt3", b"eBass1", b"eBass2", b"eBass3", b"eBass4", b"ePian1", b"ePian2", b"ePian3", b"ePian4", b"ePian5", b"Flute1", b"GapSaw", b"Grain1", b"Grain2", b"Grain3", b"Gitar1", b"Gitar2", b"Gitar3", b"Gitar4", b"Harmo1", b"Harmo2", b"Harmo3", b" LFO1", b" LFO2", b" LFO3", b" LFO4", b" LFO5", b" LFO6", b" LFO7", b" LFO8", b" LFO9", b" LFO10", b" LFO11", b" LFO12", b" LFO13", b" LFO14", b" LFO15", b" LFO16", b" LFO17", b" LFO18", b" LFO19", b" LFO20", b" LFO21", b" Misc1", b" Misc2", b" Misc3", b" Misc4", b"Noise1", b"Noise2", b"Noise3", b"Noise4", b"Noise5", b"Noise6", b" Oboes", b"Ovrto1", b"Ovrto2", b"Raw 1", b"Raw 2", b"Raw 3", b"ResPls", b"ResSaw", b"ResSqu", b"Saxoph", b"Symmtr", b"Thrmin", b"2Tone1", b"2Tone2", b"2Tone3", b"2Tone4", b"2Tone5", b"2Tone6", b"2Tone7", b"2Tone8", b"2Tone9", b"VidGm1", b"VidGm2", b"VidGm3", b"VidGm4", b"Violin", b"Vocal1", b"Vocal2", b"Vocal3", b"Vocal4", b"Vocal5", b"Vocal6", b"Vocal7" ] names = sspatcher.read_wt_names(self.test_image) self.assertEqual(len(names), sspatcher.NUM_WT) for i, name in enumerate(factory_names): self.assertEqual(names[i], name)
def test_read(self): """Read of factory wavetables works and matches data extracted from factory rom image.""" image_names = sspatcher.read_wt_names(self.test_image) image_tables = sspatcher.read_wt_data(self.test_image) wavetables = sspatcher.read_wavetables_from_files(READ_TEST_LOCATION) self.assertEquals(len(wavetables.keys()), len(image_names)) self.assertEquals(len(wavetables.values()), len(image_tables)) for name, table in wavetables.items(): self.assertIn(name, image_names) self.assertIn(table, image_tables)
def test_exceptions_from_known_bad_name_locations(self): """Correct exceptions are raised when reading names from locations known to cause them.""" sspatcher.WT_NAME_OFFSET = 0 with self.assertRaisesRegex( sspatcher.SSPatcherError, 'Found wavetable name .+ without valid prefix\.', msg= "Read from known location where names don't exist didn't raise SSPatcherError." ): sspatcher.read_wt_names(self.test_image) sspatcher.WT_NAME_OFFSET = sspatcher.IMAGE_SIZE - 64 with self.assertRaisesRegex( sspatcher.SSPatcherError, 'Got less than .+ bytes when reading wavetable names\.', msg= "Read from known location where insufficient name data can be read didn't raise SSPatcherError." ): sspatcher.read_wt_names(self.test_image)
def test_extract(self): """Full extraction process works - names and data are read and files are written successfully. This is expected to fail if the names or wavetable data aren't successfully read from the image. """ self.addCleanup(functools.partial(shutil.rmtree, TEMP_DIRECTORY)) names = sspatcher.read_wt_names(self.test_image) tables = sspatcher.read_wt_data(self.test_image) sspatcher.extract(REAL_TEST_IMAGE_PATH, TEMP_DIRECTORY) filenames = os.listdir(TEMP_DIRECTORY) self.assertEquals(len(names), len(filenames)) self.assertEquals(len(tables), len(filenames)) for filename in filenames: name = filename[:sspatcher.WT_USER_NAME_LENGTH] self.assertIn(name.encode(), names) with open('{}/{}'.format(TEMP_DIRECTORY, filename), 'rb') as f: self.assertIn(f.read(), tables)