-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
313 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,308 @@ | ||
#!/usr/bin/env python3 | ||
import unittest | ||
import shutil # rmtree, copy | ||
import os # chdir, listdir, makedirs, path, remove | ||
from subprocess import run, PIPE | ||
if __name__ == '__main__': | ||
import sys | ||
sys.path[0] = os.path.dirname(sys.path[0]) | ||
from icnsutil import RawData, PIL_ENABLED, __version__ | ||
|
||
|
||
def main(): | ||
# ensure working dir is correct | ||
os.chdir(os.path.join(os.path.dirname(__file__), 'fixtures')) | ||
print('Running tests with PIL_ENABLED =', PIL_ENABLED) | ||
unittest.main() | ||
exit() | ||
|
||
|
||
############### | ||
# CLI tests # | ||
############### | ||
|
||
def run_cli(args): # relative to fixtures folder | ||
exec_path = os.path.join(os.pardir, os.pardir, 'icnsutil', 'cli.py') | ||
return run([sys.executable, exec_path] + args, stdout=PIPE, stderr=PIPE) | ||
|
||
|
||
class TestCLI(unittest.TestCase): | ||
def test_help(self): | ||
val1 = run_cli([]).stdout | ||
val2 = run_cli(['--help']).stdout | ||
self.assertEqual(val1, val2) | ||
|
||
def test_version(self): | ||
val1 = run_cli(['--version']).stdout | ||
self.assertEqual(val1.split()[1], bytes(__version__, 'utf8')) | ||
|
||
|
||
class TestCLI_export(unittest.TestCase): | ||
def setUp(self): | ||
self.OUTDIR = 'tmp_cli_out_export' | ||
if os.path.isdir(self.OUTDIR): | ||
shutil.rmtree(self.OUTDIR) | ||
os.makedirs(self.OUTDIR, exist_ok=True) | ||
|
||
def tearDown(self): | ||
shutil.rmtree(self.OUTDIR) | ||
|
||
def assert_files(self, infile, args, sorted_out_files): | ||
r = run_cli(['e', infile, '-o', self.OUTDIR] + args) | ||
files = sorted(os.listdir(self.OUTDIR)) | ||
if r.returncode == 0: | ||
self.assertListEqual(files, sorted_out_files) | ||
return r | ||
|
||
def test_extract(self): | ||
self.assert_files('rgb.icns', [], [ | ||
'128x128-mask8b.bin', '128x128.rgb', | ||
'16x16-icon1b-mask1b.bin', '16x16-mask8b.bin', '16x16.rgb', | ||
'32x32-icon1b-mask1b.bin', '32x32-mask8b.bin', '32x32.rgb']) | ||
for size, fname in [ | ||
(64, '16x16-icon1b-mask1b.bin'), | ||
(1024, '32x32-mask8b.bin'), | ||
(14005, '128x128.rgb'), | ||
]: | ||
fsize = os.path.getsize(os.path.join(self.OUTDIR, fname)) | ||
self.assertEqual(size, fsize) | ||
|
||
def test_extract_by_key(self): | ||
self.assert_files('rgb.icns', ['-k'], [ | ||
'ICN#.bin', 'ics#.bin', 'il32.rgb', 'is32.rgb', | ||
'it32.rgb', 'l8mk.bin', 's8mk.bin', 't8mk.bin']) | ||
|
||
def test_extract_w_png(self): | ||
self.assert_files('selected.icns', [], [ | ||
'16x16.argb', '[email protected]', '18x18.argb', '[email protected]', | ||
'24x24.png', '[email protected]', '32x32.argb', '[email protected]', | ||
'info.plist', 'selected.icns']) | ||
|
||
def test_extract_png_only(self): | ||
self.assert_files('selected.icns', ['--png-only'], [ | ||
'[email protected]', '[email protected]', '24x24.png', | ||
'[email protected]', '[email protected]']) | ||
|
||
def test_extract_nested(self): | ||
self.assert_files('selected.icns', ['-r', '--png-only'], [ | ||
'[email protected]', '[email protected]', '24x24.png', | ||
'[email protected]', '[email protected]', 'selected.icns.export']) | ||
files = sorted(os.listdir( | ||
os.path.join(self.OUTDIR, 'selected.icns.export'))) | ||
self.assertListEqual(files, [ | ||
'[email protected]', '[email protected]', '24x24.png', | ||
'[email protected]', '[email protected]']) | ||
|
||
def test_extract_convert_wo_pil(self): | ||
self.assert_files('icp4rgb.icns', [], [ | ||
'16x16-mask8b.bin', '16x16.rgb', '32x32-mask8b.bin', '32x32.rgb']) | ||
|
||
@unittest.skipUnless(PIL_ENABLED, 'PIL_ENABLED == False') | ||
def test_extract_convert_w_pil(self): | ||
self.assert_files('icp4rgb.icns', ['-c'], ['16x16.png', '32x32.png']) | ||
|
||
|
||
class TestCLI_compose(unittest.TestCase): | ||
def setUp(self): | ||
self.OUTFILE = 'tmp_cli_out_compose.icns' | ||
if os.path.exists(self.OUTFILE): | ||
os.remove(self.OUTFILE) | ||
|
||
def tearDown(self): | ||
os.remove(self.OUTFILE) | ||
|
||
def test_ext_completion(self): | ||
fname = self.OUTFILE[:-5] # remove '.icns' | ||
run_cli(['c', fname, 'rgb.icns.png']) | ||
os.path.exists(self.OUTFILE) # will append .icns to filename | ||
|
||
def test_force(self): | ||
args = ['c', self.OUTFILE, 'rgb.icns.png'] | ||
r = run_cli(args) | ||
self.assertEqual(r.returncode, 0) | ||
r = run_cli(args) | ||
self.assertEqual(r.returncode, 1) # without force overwrite | ||
self.assertTrue(b'force' in r.stderr.lower()) | ||
self.assertTrue(b'-f' in r.stderr) | ||
r = run_cli(args + ['-f']) | ||
self.assertEqual(r.returncode, 0) # with force overwrite | ||
|
||
def assert_conv_file(self, fname, icns_key, arg=[]): | ||
run_cli(['c', self.OUTFILE, fname] + arg) | ||
s_orig = os.path.getsize(fname) | ||
s_icns = os.path.getsize(self.OUTFILE) | ||
is_icns = fname.endswith('.icns') | ||
self.assertEqual(s_orig + (8 if is_icns else 16), s_icns) | ||
with open(self.OUTFILE, 'rb') as fp: | ||
key, size = RawData.icns_header_read(fp.read(8)) | ||
self.assertEqual(size, s_icns) | ||
key, size = RawData.icns_header_read(fp.read(8)) | ||
self.assertEqual(size, s_orig + (0 if is_icns else 8)) | ||
self.assertEqual(key, icns_key) | ||
|
||
def test_png(self): | ||
self.assert_conv_file('rgb.icns.png', 'icp4') | ||
|
||
def test_jp2(self): | ||
self.assert_conv_file('256x256.jp2', 'ic08') | ||
self.assert_conv_file('18x18.j2k', 'icsb', arg=['-f']) | ||
|
||
def test_argb(self): | ||
self.assert_conv_file('rgb.icns.argb', 'ic04') | ||
|
||
def test_icns(self): | ||
self.assert_conv_file('selected.icns', 'slct') | ||
|
||
def test_rgb(self): | ||
self.assert_conv_file('rgb.icns.rgb', 'is32') | ||
|
||
|
||
class TestCLI_update(unittest.TestCase): | ||
def setUp(self): | ||
self.OUTFILE = 'tmp_cli_out_update.icns' | ||
if os.path.exists(self.OUTFILE): | ||
os.remove(self.OUTFILE) | ||
shutil.copy('icp4rgb.icns', self.OUTFILE) | ||
|
||
def tearDown(self): | ||
os.remove(self.OUTFILE) | ||
|
||
def test_different_outfile(self): | ||
other_out = 'tmp_cli_out_update_other.icns' | ||
run_cli(['u', '-o', other_out, self.OUTFILE, '-set', 'TOC=1']) | ||
s1 = os.path.getsize(self.OUTFILE) | ||
s2 = os.path.getsize('icp4rgb.icns') | ||
self.assertEqual(s1, s2) # outfile should not be modified! | ||
s3 = os.path.getsize(other_out) | ||
self.assertNotEqual(s1, s3) | ||
self.assertEqual(s3, s1 + (8 + 4 * 8)) | ||
os.remove(other_out) | ||
|
||
def assertUpdate(self, args, expected_diff): | ||
s1 = os.path.getsize(self.OUTFILE) | ||
run_cli(['u', self.OUTFILE] + args) | ||
s2 = os.path.getsize(self.OUTFILE) | ||
self.assertEqual(s2, s1 + expected_diff) | ||
|
||
def test_remove(self): | ||
self.assertUpdate(['-rm', 's8mk', 'l8mk'], - (256 + 8 + 1024 + 8)) | ||
|
||
def test_add(self): | ||
# dropping icns file header (-8) adding icns entry header (+8) | ||
self.assertUpdate(['-set', 'selected=selected.icns'], 15587 - 8 + 8) | ||
|
||
def test_rm_add(self): | ||
self.assertUpdate(['-set', 'Toc', '-rm', 's8mk'], 8 + 3 * 8 - 256 - 8) | ||
|
||
def test_unmodified(self): | ||
self.assertUpdate(['-rm', 'toc', 'is32', 'it32', 'il32'], 0) | ||
|
||
|
||
class TestCLI_print(unittest.TestCase): | ||
def test_single(self): | ||
ret = run_cli(['p', 'rgb.icns']).stdout | ||
for x in [b'rgb.icns', b'ICN#', b'il32', b'l8mk', b'ics#', b'is32', | ||
b's8mk', b'it32', b't8mk', b'16x16', b'32x32', b'128x128']: | ||
self.assertTrue(x in ret) | ||
for x in [b'icp4rgb.icns', b'icp4', b'icp5']: | ||
self.assertFalse(x in ret) | ||
self.assertFalse(b'offset' in ret) | ||
|
||
def test_verbose(self): | ||
ret = run_cli(['p', '-v', 'rgb.icns']).stdout | ||
self.assertTrue(b'offset' in ret) | ||
|
||
def test_multiple(self): | ||
ret = run_cli(['p', 'rgb.icns', 'icp4rgb.icns']).stdout | ||
for x in [b'rgb.icns', b'icp4rgb.icns', b'icp4', b'icp5']: | ||
self.assertTrue(x in ret) | ||
self.assertFalse(b'offset' in ret) | ||
|
||
|
||
class TestCLI_verify(unittest.TestCase): | ||
def test_ok(self): | ||
ret = run_cli(['t', 'rgb.icns']).stdout | ||
self.assertTrue(b'rgb.icns' in ret) | ||
self.assertTrue(b'OK' in ret) | ||
|
||
def test_multiple(self): | ||
ret = run_cli(['t', 'rgb.icns', 'icp4rgb.icns']).stdout | ||
self.assertTrue(b'rgb.icns' in ret) | ||
self.assertTrue(b'icp4rgb.icns' in ret) | ||
self.assertTrue(b'OK' in ret) | ||
|
||
def test_fail(self): | ||
ret = run_cli(['t', '18x18.j2k']).stdout | ||
self.assertTrue(b'18x18.j2k' in ret) | ||
self.assertTrue(b'Not an ICNS file' in ret) | ||
self.assertFalse(b'OK' in ret) | ||
|
||
def test_quiet(self): | ||
ret = run_cli(['t', '-q', 'rgb.icns', 'icp4rgb.icns']).stdout | ||
self.assertEqual(ret, b'') | ||
ret = run_cli(['t', '-q', '18x18.j2k', 'rgb.icns']).stdout | ||
self.assertTrue(b'18x18.j2k' in ret) | ||
self.assertFalse(b'rgb.icns' in ret) | ||
self.assertFalse(b'OK' in ret) | ||
|
||
|
||
@unittest.skipUnless(PIL_ENABLED, 'PIL_ENABLED == False') | ||
class TestCLI_convert(unittest.TestCase): | ||
def assertConvert(self, source, ext): | ||
dest = 'tmp_cli_out_convert.' + ext | ||
run_cli(['img', dest, source]).stdout | ||
self.assertTrue(os.path.exists(dest)) | ||
s = os.path.getsize(dest) | ||
os.remove(dest) | ||
return s | ||
|
||
def test_to_png(self): | ||
for expected_size, fname in [ | ||
(103, '18x18.j2k'), | ||
(4778, '256x256.jp2'), | ||
(813, 'rgb.icns.png'), | ||
(813, 'rgb.icns.rgb'), | ||
]: | ||
size = self.assertConvert(fname, 'png') | ||
self.assertEqual(size, expected_size) | ||
|
||
def test_to_argb(self): | ||
for expected_size, fname in [ | ||
(822, '18x18.j2k'), | ||
(14865, '256x256.jp2'), | ||
(713, 'rgb.icns.png'), | ||
(713, 'rgb.icns.rgb'), | ||
]: | ||
size = self.assertConvert(fname, 'argb') | ||
self.assertEqual(size, expected_size) | ||
|
||
def test_to_rgb(self): | ||
for expected_size, fname, expected_mask_size in [ | ||
(812, '18x18.j2k', 324), | ||
(13851, '256x256.jp2', 65536), | ||
(705, 'rgb.icns.png', 256), | ||
(705, 'rgb.icns.rgb', 256), | ||
]: | ||
size = self.assertConvert(fname, 'rgb') | ||
self.assertEqual(size, expected_size) | ||
mask_size = os.path.getsize('tmp_cli_out_convert.rgb.mask') | ||
self.assertEqual(mask_size, expected_mask_size) | ||
os.remove('tmp_cli_out_convert.rgb.mask') | ||
|
||
def test_without_dest_name(self): | ||
src = 'tmp_cli_out_convert.jp2' | ||
shutil.copy('18x18.j2k', src) | ||
for ext, size in [('png', 103), ('argb', 822), ('rgb', 812)]: | ||
run_cli(['img', ext, src]).stdout | ||
self.assertTrue(os.path.exists(src + '.' + ext)) | ||
self.assertEqual(os.path.getsize(src + '.' + ext), size) | ||
os.remove(src + '.' + ext) | ||
os.remove(src) | ||
# test if mask was created | ||
self.assertTrue(os.path.exists(src + '.rgb.mask')) | ||
self.assertEqual(os.path.getsize(src + '.rgb.mask'), 324) | ||
os.remove(src + '.rgb.mask') | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |