1#!/usr/bin/env python 2# Copyright 2013 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import fnmatch 7import tempfile 8import unittest 9import zipfile 10 11import md5_check # pylint: disable=W0403 12 13 14def _WriteZipFile(path, entries): 15 with zipfile.ZipFile(path, 'w') as zip_file: 16 for subpath, data in entries: 17 zip_file.writestr(subpath, data) 18 19 20class TestMd5Check(unittest.TestCase): 21 def setUp(self): 22 self.called = False 23 self.changes = None 24 25 def testCallAndRecordIfStale(self): 26 input_strings = ['string1', 'string2'] 27 input_file1 = tempfile.NamedTemporaryFile(suffix='.txt') 28 input_file2 = tempfile.NamedTemporaryFile(suffix='.zip') 29 file1_contents = 'input file 1' 30 input_file1.write(file1_contents) 31 input_file1.flush() 32 # Test out empty zip file to start. 33 _WriteZipFile(input_file2.name, []) 34 input_files = [input_file1.name, input_file2.name] 35 36 record_path = tempfile.NamedTemporaryFile(suffix='.stamp') 37 38 def CheckCallAndRecord(should_call, message, force=False, 39 outputs_specified=False, outputs_missing=False, 40 expected_changes=None, added_or_modified_only=None): 41 output_paths = None 42 if outputs_specified: 43 output_file1 = tempfile.NamedTemporaryFile() 44 if outputs_missing: 45 output_file1.close() # Gets deleted on close(). 46 output_paths = [output_file1.name] 47 48 self.called = False 49 self.changes = None 50 if expected_changes or added_or_modified_only is not None: 51 def MarkCalled(changes): 52 self.called = True 53 self.changes = changes 54 else: 55 def MarkCalled(): 56 self.called = True 57 58 md5_check.CallAndRecordIfStale( 59 MarkCalled, 60 record_path=record_path.name, 61 input_paths=input_files, 62 input_strings=input_strings, 63 output_paths=output_paths, 64 force=force, 65 pass_changes=(expected_changes or added_or_modified_only) is not None) 66 self.assertEqual(should_call, self.called, message) 67 if expected_changes: 68 description = self.changes.DescribeDifference() 69 self.assertTrue(fnmatch.fnmatch(description, expected_changes), 70 'Expected %s to match %s' % ( 71 repr(description), repr(expected_changes))) 72 if should_call and added_or_modified_only is not None: 73 self.assertEqual(added_or_modified_only, 74 self.changes.AddedOrModifiedOnly()) 75 76 CheckCallAndRecord(True, 'should call when record doesn\'t exist', 77 expected_changes='Previous stamp file not found.', 78 added_or_modified_only=False) 79 CheckCallAndRecord(False, 'should not call when nothing changed') 80 CheckCallAndRecord(False, 'should not call when nothing changed #2', 81 outputs_specified=True, outputs_missing=False) 82 CheckCallAndRecord(True, 'should call when output missing', 83 outputs_specified=True, outputs_missing=True, 84 expected_changes='Outputs do not exist:*', 85 added_or_modified_only=False) 86 CheckCallAndRecord(True, force=True, message='should call when forced', 87 expected_changes='force=True', 88 added_or_modified_only=False) 89 90 input_file1.write('some more input') 91 input_file1.flush() 92 CheckCallAndRecord(True, 'changed input file should trigger call', 93 expected_changes='*Modified: %s' % input_file1.name, 94 added_or_modified_only=True) 95 96 input_files = input_files[::-1] 97 CheckCallAndRecord(False, 'reordering of inputs shouldn\'t trigger call') 98 99 input_files = input_files[:1] 100 CheckCallAndRecord(True, 'removing file should trigger call', 101 expected_changes='*Removed: %s' % input_file1.name, 102 added_or_modified_only=False) 103 104 input_files.append(input_file1.name) 105 CheckCallAndRecord(True, 'added input file should trigger call', 106 expected_changes='*Added: %s' % input_file1.name, 107 added_or_modified_only=True) 108 109 input_strings[0] = input_strings[0] + ' a bit longer' 110 CheckCallAndRecord(True, 'changed input string should trigger call', 111 expected_changes='*Input strings changed*', 112 added_or_modified_only=False) 113 114 input_strings = input_strings[::-1] 115 CheckCallAndRecord(True, 'reordering of string inputs should trigger call', 116 expected_changes='*Input strings changed*') 117 118 input_strings = input_strings[:1] 119 CheckCallAndRecord(True, 'removing a string should trigger call') 120 121 input_strings.append('a brand new string') 122 CheckCallAndRecord(True, 'added input string should trigger call') 123 124 _WriteZipFile(input_file2.name, [('path/1.txt', '1')]) 125 CheckCallAndRecord(True, 'added subpath should trigger call', 126 expected_changes='*Modified: %s*Subpath added: %s' % ( 127 input_file2.name, 'path/1.txt'), 128 added_or_modified_only=True) 129 _WriteZipFile(input_file2.name, [('path/1.txt', '2')]) 130 CheckCallAndRecord(True, 'changed subpath should trigger call', 131 expected_changes='*Modified: %s*Subpath modified: %s' % ( 132 input_file2.name, 'path/1.txt'), 133 added_or_modified_only=True) 134 CheckCallAndRecord(False, 'should not call when nothing changed') 135 136 _WriteZipFile(input_file2.name, []) 137 CheckCallAndRecord(True, 'removed subpath should trigger call', 138 expected_changes='*Modified: %s*Subpath removed: %s' % ( 139 input_file2.name, 'path/1.txt'), 140 added_or_modified_only=False) 141 142 143if __name__ == '__main__': 144 unittest.main() 145