diff --git a/tests/README-TESTS.md b/tests/README-TESTS.md index a7324377..408ae3ec 100644 --- a/tests/README-TESTS.md +++ b/tests/README-TESTS.md @@ -39,6 +39,7 @@ for Python 2). Then navigate to the `tests/` subdirectory and run: ``` shell +python3 -m pip install -r requirements.txt python3 runner.py ``` diff --git a/tests/bash_tests/testcases.py b/tests/bash_tests/testcases.py index 8362a294..b9172f00 100644 --- a/tests/bash_tests/testcases.py +++ b/tests/bash_tests/testcases.py @@ -231,12 +231,12 @@ class TestCases(unittest.TestCase): out += BT.Executer('exiv2 -M"del Xmp.mwg-rs.Regions" DSC_3079.jpg') out += BT.Executer('exiv2 -px DSC_3079.jpg') - # Ignore the output differences on Windows + # Ignore output differences on Windows for pair in [ - ('charset="Jis"', 'charset=Jis'), + ('charset="Jis"' , 'charset=Jis'), ('charset="Unicode"', 'charset=Unicode'), - (' 9 Rocknroll', "11 Rock'n'roll"), - ('Rocknroll', "Rock'n'roll") + (' 9 Rocknroll' , "11 Rock'n'roll"), + ('Rocknroll' , "Rock'n'roll") ]: out = str(out).replace(pair[0], pair[1]) @@ -374,18 +374,18 @@ set Exif.Photo.DateTimeDigitized 2020:05:26 07:31:42 out += BT.Executer('exiv2 -u -v print {images_2_str}', vars(), assert_returncode=[253]) out += '' out += BT.Executer('exiv2 -u -v -b -pt print {images_2_str}', vars()) - e = BT.Executer('exiv2 -u -v -b -pt print {images_2_str}', vars(), redirect_stderr_to_stdout=False) + e = BT.Executer('exiv2 -u -v -b -pt print {images_2_str}', vars(), redirect_stderr_to_stdout=False, decode_output=False) BT.save(e.stdout, 'iii') - out += e.stderr + out += e.stderr.decode() out += '\nExtract Exif data --------------------------------------------------------' out += BT.Executer('exiv2 -u -vf extract {images_2_str}', vars()) out += '\nExtract Thumbnail --------------------------------------------------------' out += BT.Executer('exiv2 -u -vf -et extract {images_2_str}', vars(), assert_returncode=[253]) - e = BT.Executer('exiv2 -u -v -b -pt print {images_3_str}', vars(), redirect_stderr_to_stdout=False) + e = BT.Executer('exiv2 -u -v -b -pt print {images_3_str}', vars(), redirect_stderr_to_stdout=False, decode_output=False) BT.save(e.stdout, 'jjj') - out += e.stderr + out += e.stderr.decode() out += '\nCompare image data and extracted data ------------------------------------' out += BT.diff('iii', 'jjj') @@ -400,9 +400,9 @@ set Exif.Photo.DateTimeDigitized 2020:05:26 07:31:42 out += '\nInsert Exif data ---------------------------------------------------------' out += BT.Executer('exiv2 -u -v insert {images_2_str}', vars()) - e = BT.Executer('exiv2 -u -v -b -pt print {images_3_str}', vars(), redirect_stderr_to_stdout=False) + e = BT.Executer('exiv2 -u -v -b -pt print {images_3_str}', vars(), redirect_stderr_to_stdout=False, decode_output=False) BT.save(e.stdout, 'kkk') - out += e.stderr + out += e.stderr.decode() out += '\nCompare original and inserted image data ---------------------------------' out += BT.diff('iii', 'kkk') @@ -472,7 +472,7 @@ set Exif.Photo.DateTimeDigitized 2020:05:26 07:31:42 BT.copyTestFile(i) out += BT.Executer('exiv2 -pS {img}', vars()) - e = BT.Executer('exiv2 -pC {img}', vars(), adjust_output=False, decode_output=False) + e = BT.Executer('exiv2 -pC {img}', vars(), compatible_output=False, decode_output=False) BT.save(e.stdout, stub + '_1.icc') out += BT.Executer('exiv2 -eC --force {img}', vars()) BT.mv(iccname, stub + '_2.icc') @@ -480,7 +480,7 @@ set Exif.Photo.DateTimeDigitized 2020:05:26 07:31:42 BT.copyTestFile('large.icc', iccname) out += BT.Executer('exiv2 -iC {img}', vars()) - e = BT.Executer('exiv2 -pC {img}', vars(), adjust_output=False, decode_output=False) + e = BT.Executer('exiv2 -pC {img}', vars(), compatible_output=False, decode_output=False) BT.save(e.stdout, stub + '_large_1.icc') out += BT.Executer('exiv2 -pS {img}', vars()) out += BT.Executer('exiv2 -eC --force {img}', vars()) @@ -489,7 +489,7 @@ set Exif.Photo.DateTimeDigitized 2020:05:26 07:31:42 BT.copyTestFile('small.icc', iccname) out += BT.Executer('exiv2 -iC {img}', vars()) - e = BT.Executer('exiv2 -pC {img}', vars(), adjust_output=False, decode_output=False) + e = BT.Executer('exiv2 -pC {img}', vars(), compatible_output=False, decode_output=False) BT.save(e.stdout, stub + '_small_1.icc') out += BT.Executer('exiv2 -pS {img}', vars()) out += BT.Executer('exiv2 -eC --force {img}', vars()) @@ -947,3 +947,364 @@ set Exif.Photo.DateTimeDigitized 2020:05:26 07:31:42 BT.reportTest('preview-test', out) + + def stdin_test(self): + # Test driver for stdin + try: + import lxml + except ModuleNotFoundError: + print('ignored') + print('Missing module lxml, please install: `pip install lxml`') + return + + out = BT.Output() + a = 'exiv2-bug1229.jpg' # jpg with 2 APP1/xap segments + b = 'girl.jpg' + BT.copyTestFile(a) + + def get_xmpData(img): + e = BT.Executer('exiv2 -pX {img}', vars(), decode_output=False) + return e.stdout.replace(b'\n', b'\r\n', 16) # Ignore the difference in newline + + BT.copyTestFile(a, b) + out += BT.Executer('exiv2 -pS {b}', vars()) + out += BT.Executer('exiv2 -dX {b}', vars()) # remove first + out += BT.Executer('exiv2 -pS {b}', vars()) + + e = BT.Executer('exiv2 -pX {a}', vars(), decode_output=False) + with open('out2', 'wb') as f: + f.write(e.stdout) + + out += BT.Executer('exiv2 -iXX- {b}', vars(), stdin=get_xmpData(a)) + out += BT.Executer('exiv2 -pS {b}', vars()) + + BT.copyTestFile(a, b) + out += BT.Executer('exiv2 -dX {b}', vars()) + out += BT.Executer('exiv2 -dX {b}', vars()) + out += BT.Executer('exiv2 -pS {b}', vars()) + out += BT.Executer('exiv2 -iXX- {b}', vars(), stdin=get_xmpData(a)) + out += BT.Executer('exiv2 -pS {b}', vars()) + + for f in ['Reagan.jpg', 'Reagan.tiff', 'ReaganSmallPng.png']: + BT.copyTestFile(f) + out += BT.Executer('exiv2 -iXX- {f}', vars(), stdin=get_xmpData(a)) + e = BT.Executer('exiv2 -pX {f}', vars()) + out += """ + + +{} + +""".strip('\n').format(BT.pretty_xml(e.stdout)) + + for f in ['Reagan.jpg', 'ReaganSmallPng.png']: + BT.copyTestFile(f) + BT.copyTestFile(a, b) + out += BT.Executer('exiv2 -pS {b}', vars()) + e = BT.Executer('exiv2 -ea- {f}', vars(), decode_output=False) + out += BT.Executer('exiv2 -ia- {b}', vars(), stdin=e.stdout) + out += BT.Executer('exiv2 -pS {b}', vars()) + + BT.copyTestFile('Reagan.tiff') # 1272 ReaganLargeTiff.tiff + for img in ['Reagan.jpg', 'ReaganSmallPng.png', 'exiv2-bug1199.webp']: + BT.copyTestFile(img) + e = BT.Executer('exiv2 -eC- Reagan.tiff', decode_output=False) + + # Ignore the difference in the path separator + stdout = e.stdout + for pair in [ + (b'\x03/\x9e', b'\x03\\\x9e'), + (b'\x0c/\x0c', b'\x0c\\\x0c'), + (b'V/V' , b'V\\V' ), + (b'\xe5/5' , b'\xe5\\5' ), + (b'5/\x86' , b'5\\\x86' ), + (b'\x86/\xd6', b'\x86\\\xd6'), + (b'\xac/\xac', b'\xac\\\xac'), + (b'\xd7/\xd7', b'\xd7\\\xd7'), + ]: + stdout = stdout.replace(pair[0], pair[1]) + + out += BT.Executer('exiv2 -iC- {img}', vars(), stdin=stdout) + out += BT.Executer('exiv2 -pS {img}', vars()) + if img == 'ReaganSmallPng.png': + with open('out2', 'wb') as f: + f.write(e.stdout) + + BT.reportTest('stdin-test', out) + + + def stringto_test(self): + # Test driver for tests of stringToLong/Float/Rational + out = BT.Output() + out += BT.Executer('stringto-test') + BT.reportTest('stringto-test', out) + + + def tiff_test(self): + # TIFF parser test driver + + def exifprobe(img): + out = BT.Output() + + # Convert each line from that format: + # Exif.Image.NewSubfileType Long 1 Primary image + # to that format: + # NewSubfileType Long 1 "Primary image" + tags = [] + typs = [] + lens = [] + vals = [] + e = BT.Executer('exiv2 -pa {img}', vars(), redirect_stderr_to_stdout=False) + for line in e.stdout.split('\n'): + fields = re.findall(r'^(\S*)\s*(\S*)\s*(\d*)\s*(.*)$', line)[0] + tags += [fields[0].split('.')[2]] # tag + typs += [fields[1]] # type + lens += [fields[2]] # length + vals += [fields[3]] # value + + out += 'exiv2 -pa output' + for i in range(len(tags)): + out += ' \t '.join([tags[i], typs[i], lens[i], '"{}"'.format(vals[i])]) + + # Parse -pS output: + # address | tag | type | count | offset | value + # 254 | 0x00fe NewSubfileType | LONG | 1 | 0 | 0 + TAGS = [] + TYPS = [] + LENS = [] + VALS = [] + e = BT.Executer('exiv2 -pS {img}', vars(), redirect_stderr_to_stdout=False) + for line in e.stdout.split('\n')[2:-1]: + fields = [i.strip(' ') for i in line.split('|')] + TAGS += [fields[1].split(' ')[1]] + TYPS += [fields[2]] + LENS += [fields[3]] + VALS += [fields[5]] + + out += '\nexiv2 -pS output' + for i in range(len(TAGS)): + out += ' \t '.join([TAGS[i], TYPS[i], LENS[i], '"{}"'.format(VALS[i])]) + + out += '\nAnalysis' + out += 'count = {} COUNT = {}'.format(len(tags), len(TAGS)) + + # Make them have the same number of lines + max_lines = max(len(TAGS), len(tags)) + for _list in [tags, typs, lens, vals, TAGS, TYPS, LENS, VALS]: + _list += [''] * (max_lines - len(_list)) + + # Compare the main fields of each line + for i in range(max_lines): + if TAGS[i] != tags[i]: + out += 'TAG {} {} mismatch'.format(TAGS[i], tags[i]).replace(' ', ' ') + + TYPS[i] = TYPS[i].upper() + typs[i] = typs[i].upper() + if TYPS[i] != typs[i]: + out += 'TYPE {} {} mismatch'.format(TYPS[i], typs[i]).replace(' ', ' ') + + if LENS[i] != lens[i]: + out += 'Length {} {} mismatch'.format(LENS[i], lens[i]).replace(' ', ' ') + + if typs[i] == 'ASCII' and VALS[i] != vals[i]: + out += 'Value {} {} mismatch'.format(VALS[i], vals[i]).replace(' ', ' ') + + return str(out) + + test_file = 'mini9.tif' + BT.copyTestFile(test_file) + out = BT.Output() + out += exifprobe(test_file) + out += BT.Executer('tiff-test {test_file}', vars()) + out += exifprobe(test_file) + BT.reportTest('tiff-test', out) + + + def version_test(self): + # Test driver for exiv2 --verbose --version + out = BT.Output() + out += BT.Executer('exiv2 --verbose --version') + + + def webp_test(self): + # Test driver for webp + webp = 'exiv2-bug1199.webp' # http://dev.exiv2.org/attachments/download/1033/Stonehenge-with-icc.webp + icc = 'exiv2-bug1199.icc' + exv = 'exiv2-bug1199.exv' + xmp = 'exiv2-bug1199.xmp' + tiff = 'Reagan.tiff' + out = BT.Output() + + # Extract the XMP + BT.copyTestFile(webp) + out += BT.Executer('exiv2 -pS {webp}', vars()) + e = BT.Executer('exiv2 -pX {webp}', vars()) + out += """ + + +{} + +""".strip('\n').format(BT.pretty_xml(e.stdout)) + + # Test deleting metadata + for option in ['-dC', '-de', '-dx', '-dCe', '-dCx', '-dCxe']: + BT.copyTestFile(webp) + out += BT.Executer('exiv2 -pS {webp}', vars()) + out += BT.Executer('exiv2 {option} {webp}', vars()) + out += BT.Executer('exiv2 -pS {webp}', vars()) + + # Extract the icc + BT.copyTestFile(webp) + BT.copyTestFile(tiff) + out += BT.Executer('exiv2 -pS {webp}', vars()) + BT.save( BT.Executer('exiv2 -pC {tiff}', vars(), decode_output=False).stdout, icc) + out += BT.Executer('exiv2 -iC {webp}', vars()) + out += BT.Executer('exiv2 -pS {webp}', vars()) + + # Copy the XMP from the test file + BT.copyTestFile(webp) + BT.save( BT.Executer('exiv2 -pX {webp}', vars(), decode_output=False).stdout, xmp) + out += BT.Executer('exiv2 -ea --force {webp}', vars()) + + BT.copyTestFile(webp) + out += BT.Executer('exiv2 -pS {webp}', vars()) + out += BT.Executer('exiv2 -iXX {webp}', vars()) + out += BT.Executer('exiv2 -pS {webp}', vars()) + out += BT.Executer('exiv2 -ix {webp}', vars()) + + # Copy the XMP from Reagan.tiff to test file + BT.copyTestFile(tiff) + BT.save( BT.Executer('exiv2 -pX {tiff}', vars(), decode_output=False).stdout, xmp) + out += BT.Executer('exiv2 -ea --force {tiff}', vars()) + BT.mv('Reagan.exv', exv) + + BT.copyTestFile(webp) + out += BT.Executer('exiv2 -pS {webp}', vars()) + out += BT.Executer('exiv2 -iXX {webp}', vars()) + out += BT.Executer('exiv2 -pS {webp}', vars()) + out += BT.Executer('exiv2 -ix {webp}', vars()) + + # Copy the XMP from exiv2-bug922.jpg to test file + BT.copyTestFile('exiv2-bug922.jpg') + BT.save( BT.Executer('exiv2 -pX exiv2-bug922.jpg', decode_output=False).stdout, xmp) + BT.Executer( 'exiv2 -ea --force exiv2-bug922.jpg') + BT.mv('exiv2-bug922.exv', exv) + + BT.copyTestFile(webp) + out += BT.Executer('exiv2 -pS {webp}', vars()) + out += BT.Executer('exiv2 -ix {webp}', vars()) + out += BT.Executer('exiv2 -pS {webp}', vars()) + out += BT.Executer('exiv2 -iXX {webp}', vars()) + out += BT.Executer('exiv2 -pS {webp}', vars()) + + BT.copyTestFile('exiv2-bug922.jpg', webp) + out += BT.Executer('exiv2 --force -ea {webp}', vars()) + BT.copyTestFile(webp) + out += BT.Executer('exiv2 -pS {webp}', vars()) + out += BT.Executer('exiv2 -ie {webp}', vars()) + out += BT.Executer('exiv2 -pS {webp}', vars()) + + BT.reportTest('webp-test', out) + + + def write_test(self): + # Test driver for the write unit tests + images = [ + 'exiv2-canon-powershot-s40.jpg' + ,'exiv2-kodak-dc210.jpg' + ,'exiv2-fujifilm-finepix-s2pro.jpg' + ,'exiv2-sigma-d10.jpg' + ,'exiv2-nikon-e990.jpg' + ,'exiv2-nikon-d70.jpg' + ,'exiv2-nikon-e950.jpg' + ] + for i in images: + BT.copyTestFile(i) + + out = BT.Output() + out += BT.runTestCase( 1, 'exiv2-canon-powershot-s40.jpg') + out += BT.runTestCase( 2, 'exiv2-canon-powershot-s40.jpg') + out += BT.runTestCase( 3, 'exiv2-kodak-dc210.jpg') + out += BT.runTestCase( 4, 'exiv2-canon-powershot-s40.jpg') + out += BT.runTestCase( 5, 'exiv2-canon-powershot-s40.jpg') + out += BT.runTestCase( 6, 'exiv2-kodak-dc210.jpg') + out += BT.runTestCase( 7, 'exiv2-fujifilm-finepix-s2pro.jpg') + out += BT.runTestCase( 8, 'exiv2-sigma-d10.jpg') + out += BT.runTestCase( 9, 'exiv2-nikon-e990.jpg') + out += BT.runTestCase(10, 'exiv2-nikon-e950.jpg') + out += BT.runTestCase(11, 'exiv2-nikon-d70.jpg') + + # Adjust the output to be compatible with the reference output + out = str(out) + for img in images: + out = out.replace('Reading file ' + img, 'Reading file ./' + img) + + # Ignore output differences between BT.diff() and GNU dIff + for pair in [ + ('24,2c24,2', '24,25c24,25'), + ('29,2c29,2', '29,30c29,30'), + ('27,2c27,2', '27,28c27,28'), + ('28,2c28,2', '28,29c28,29'), + ]: + out = out.replace(pair[0], pair[1]) + + BT.reportTest('write-test', out) + + + def write2_test(self): + # Test driver for write unit tests to build Exif metadata from scratch + img = 'exiv2-empty.jpg' + BT.copyTestFile(img) + out = BT.Output() + out += BT.Executer('write2-test {img}', vars()) + BT.reportTest('write2-test', out) + + + def xmpparser_test(self): + # XMP parser test driver + images = ['BlueSquare.xmp', 'StaffPhotographer-Example.xmp', 'xmpsdk.xmp'] + out = BT.Output() + + for img in images: + BT.copyTestFile(img) + out += BT.Executer('xmpparser-test {img}', vars()) + out += BT.diff(img, img + '-new') + + xmp = 'xmpsdk.xmp' + BT.save(BT.Executer('xmpparse {xmp}' , vars()).stdout, 't1') + BT.save(BT.Executer('xmpparse {xmp}-new', vars()).stdout, 't2') + out += BT.diff('t1', 't2') + + out += BT.Executer('xmpsample') + for img in ['exiv2-empty.jpg', 'cmdxmp.txt']: + BT.copyTestFile(img) + out += BT.Executer('exiv2 -v -m cmdxmp.txt exiv2-empty.jpg', assert_returncode=[0, 1]) + out += BT.Executer('exiv2 -v -px exiv2-empty.jpg') + + # Ignore output differences between BT.diff() and GNU dIff + out = str(out) + out = out.replace(""" +34,0c35 +--- +> Blue Square Test File - .jpg +36c36,0 +< Blue Square Test File - .jpg +67,21c67,21 +""".strip('\n'), +""" +35d34 +< Blue Square Test File - .jpg +36a36 +> Blue Square Test File - .jpg +67,87c67,87 +""".strip('\n')) + for pair in [ + ('46,0c47\n---' , '46a47'), + ('160,32c161' , '160,191c161'), + ('1,49c1,65' , '1,48c1,65'), + ('< \n< ' , '< '), + ('> \n' , '> \n/ No newline at end of file'), + ]: + out = out.replace(pair[0], pair[1]) + + BT.reportTest('xmpparser-test', out) + diff --git a/tests/bash_tests/utils.py b/tests/bash_tests/utils.py index 4bb7f61c..73ecae3c 100644 --- a/tests/bash_tests/utils.py +++ b/tests/bash_tests/utils.py @@ -158,7 +158,7 @@ def diff(file1, file2, encoding=None): output = [] new_part = True num = 0 - for line in difflib.unified_diff(text1, text2, fromfile=file1, tofile=file2, lineterm=''): + for line in difflib.unified_diff(text1, text2, fromfile=file1, tofile=file2, n=0, lineterm=''): num += 1 if num < 3: # line = line.replace('--- ', '<<< ') @@ -207,7 +207,7 @@ def diff_bytes(file1, file2, return_str=False): new_part = True num = 0 for line in difflib.diff_bytes(difflib.unified_diff, text1, text2, - fromfile=file1.encode(), tofile=file2.encode(), lineterm=b''): + fromfile=file1.encode(), tofile=file2.encode(), n=0, lineterm=b''): num += 1 if num < 3: line = line.decode() @@ -249,6 +249,17 @@ def md5sum(filename): return hashlib.md5(f.read()).hexdigest() +def pretty_xml(text, encoding=None): + """ + Add indent to the XML text + """ + from lxml import etree + encoding = encoding or Config.encoding + root = etree.fromstring(text) + etree.indent(root) + return etree.tostring(root).decode(encoding) + + class Log: def __init__(self): @@ -331,17 +342,22 @@ def diffCheck(file1, file2, in_bytes=False, encoding=None): def simply_diff(file1, file2, encoding=None): """ Find the first different line of the two text files """ - encoding = encoding or Config.encoding - list1 = cat(file1, encoding=encoding).split('\n') - list2 = cat(file2, encoding=encoding).split('\n') - if list1 == list2: + encoding = encoding or Config.encoding + list1 = cat(file1, encoding=encoding).split('\n') + list2 = cat(file2, encoding=encoding).split('\n') + if list1 == list2: return - report = [] - report += ['{}: {} lines'.format(file1, len(list1))] - report += ['{}: {} lines'.format(file2, len(list2))] - max_lines = max(len(list1), len(list2)) - for i in [list1, list2]: - i += [''] * (max_lines - len(i)) # Make them have the same number of lines + + report = [] + report += ['{}: {} lines'.format(file1, len(list1))] + report += ['{}: {} lines'.format(file2, len(list2))] + + # Make them have the same number of lines + max_lines = max(len(list1), len(list2)) + for _list in [list1, list2]: + _list += [''] * (max_lines - len(_list)) + + # Compare each line for i in range(max_lines): if list1[i] != list2[i]: report += ['The first mismatch is in line {}:'.format(i + 1)] @@ -353,10 +369,10 @@ def simply_diff(file1, file2, encoding=None): class Executer: """ - Execute a command in the shell, return a decorated `Subprocess.Popen` object. + Execute a command in the shell, return a `Executer` object. - If a binary of Exiv2 is executed, the absolute path is automatically added. - - `adjust_output`: whether to filter path delimiters, whitespace characters in output - - `decode_output`: whether to decode output from bytes to str + - `compatible_output=True`: filter out path delimiters, whitespace characters in output + - `decode_output=True`: decode output from bytes to str Sample: >>> Executer('echo Hello').stdout @@ -370,7 +386,7 @@ class Executer: stdin: (str, bytes) = None, redirect_stderr_to_stdout=True, assert_returncode=[0], - adjust_output=True, + compatible_output=True, decode_output=True): self.cmd = cmd.format(**vars_dict) self.cwd = cwd or Config.tmp_dir @@ -381,8 +397,8 @@ class Executer: self.redirect_stderr_to_stdout = redirect_stderr_to_stdout self.assert_returncode = assert_returncode # self.returncode = 0 - self.adjust_output = adjust_output - self.decode_output = decode_output + self.compatible_output = compatible_output + self.decode_output = decode_output # Generate the args for subprocess.Popen args = self.cmd.split(' ', maxsplit=1) @@ -424,7 +440,7 @@ class Executer: output = [i.rstrip(b'\r\n').rstrip(b'\n') for i in output] # Remove the last line break of the output # Extract stdout and stderr - if self.adjust_output: + if self.compatible_output: output = [i.replace(b'\r\n', b'\n') for i in output] # Fix dos line-endings output = [i.replace(b'\\', rb'/') for i in output] # Fix dos path separators if self.decode_output: @@ -594,3 +610,27 @@ def extendedTest(filename): e = Executer('iptcprint {tmp}', vars(), decode_output=False) save(e.stdout + b'\n', test_file) return diffCheck(good_file, test_file, in_bytes=True) + + +def runTestCase(num, img): + """ Run the requested test case number with the given image """ + out_img = 'test{}.jpg'.format(num) + thumb_jpg = 'thumb{}.jpg'.format(num) + thumb_tif = 'thumb{}.tif'.format(num) + rm(out_img, thumb_jpg, thumb_tif) + rm('iii', 'ttt') + cp(img, out_img) + out = Output() + out += '------------------------------------------------------------' + + e = Executer('exifprint {img}', vars(), redirect_stderr_to_stdout=False, decode_output=False) + out += e.stderr.decode() if e.stderr else None + save(e.stdout, 'iii') + + e = Executer('write-test {img} {num}', vars(), redirect_stderr_to_stdout=False, decode_output=False) + out += e.stderr.decode() if e.stderr else None + save(e.stdout, 'ttt') + + out += diff('iii', 'ttt') + return str(out) + diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 00000000..ab90481d --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1 @@ +lxml