1# Copyright 2019 The Chromium Authors 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import os 6import tempfile 7import unittest 8 9import mock 10import version 11 12 13def _ReplaceArgs(args, *replacements): 14 new_args = args[:] 15 for flag, val in replacements: 16 flag_index = args.index(flag) 17 new_args[flag_index + 1] = val 18 return new_args 19 20 21class _VersionTest(unittest.TestCase): 22 """Unittests for the version module. 23 """ 24 25 _CHROME_VERSION_FILE = os.path.join( 26 os.path.dirname(__file__), os.pardir, os.pardir, 'chrome', 'VERSION') 27 28 _SCRIPT = os.path.join(os.path.dirname(__file__), 'version.py') 29 30 _EXAMPLE_VERSION = { 31 'MAJOR': '74', 32 'MINOR': '0', 33 'BUILD': '3720', 34 'PATCH': '0', 35 } 36 37 _EXAMPLE_TEMPLATE = ( 38 'full = "@MAJOR@.@MINOR@.@BUILD@.@PATCH@" ' 39 'major = "@MAJOR@" minor = "@MINOR@" ' 40 'build = "@BUILD@" patch = "@PATCH@" version_id = @VERSION_ID@ ') 41 42 _ANDROID_CHROME_VARS = [ 43 'chrome_version_code', 44 'monochrome_version_code', 45 'trichrome_version_code', 46 'webview_stable_version_code', 47 'webview_beta_version_code', 48 'webview_dev_version_code', 49 ] 50 51 _EXAMPLE_ANDROID_TEMPLATE = ( 52 _EXAMPLE_TEMPLATE + ''.join( 53 ['%s = "@%s@" ' % (el, el.upper()) for el in _ANDROID_CHROME_VARS])) 54 55 _EXAMPLE_ARGS = [ 56 '-f', 57 _CHROME_VERSION_FILE, 58 '-t', 59 _EXAMPLE_TEMPLATE, 60 ] 61 62 _EXAMPLE_ANDROID_ARGS = _ReplaceArgs(_EXAMPLE_ARGS, 63 ['-t', _EXAMPLE_ANDROID_TEMPLATE]) + [ 64 '-a', 65 'arm', 66 '--os', 67 'android', 68 ] 69 70 @staticmethod 71 def _RunBuildOutput(new_version_values={}, 72 get_new_args=lambda old_args: old_args): 73 """Parameterized helper method for running the main testable method in 74 version.py. 75 76 Keyword arguments: 77 new_version_values -- dict used to update _EXAMPLE_VERSION 78 get_new_args -- lambda for updating _EXAMPLE_ANDROID_ARGS 79 """ 80 81 with mock.patch('version.FetchValuesFromFile') as \ 82 fetch_values_from_file_mock: 83 84 fetch_values_from_file_mock.side_effect = (lambda values, file : 85 values.update( 86 dict(_VersionTest._EXAMPLE_VERSION, **new_version_values))) 87 88 new_args = get_new_args(_VersionTest._EXAMPLE_ARGS) 89 return version.BuildOutput(new_args) 90 91 def testFetchValuesFromFile(self): 92 """It returns a dict in correct format - { <str>: <str> }, to verify 93 assumption of other tests that mock this function 94 """ 95 result = {} 96 version.FetchValuesFromFile(result, self._CHROME_VERSION_FILE) 97 98 for key, val in result.items(): 99 self.assertIsInstance(key, str) 100 self.assertIsInstance(val, str) 101 102 def testBuildOutputAndroid(self): 103 """Assert it gives includes assignments of expected variables""" 104 output = self._RunBuildOutput( 105 get_new_args=lambda args: self._EXAMPLE_ANDROID_ARGS) 106 contents = output['contents'] 107 108 self.assertRegex(contents, r'\bchrome_version_code = "\d+"\s') 109 self.assertRegex(contents, r'\bmonochrome_version_code = "\d+"\s') 110 self.assertRegex(contents, r'\btrichrome_version_code = "\d+"\s') 111 self.assertRegex(contents, r'\bwebview_stable_version_code = "\d+"\s') 112 self.assertRegex(contents, r'\bwebview_beta_version_code = "\d+"\s') 113 self.assertRegex(contents, r'\bwebview_dev_version_code = "\d+"\s') 114 115 def testBuildOutputAndroidArchVariantsArm64(self): 116 """Assert 64-bit-specific version codes""" 117 new_template = ( 118 self._EXAMPLE_ANDROID_TEMPLATE + 119 "monochrome_64_32_version_code = \"@MONOCHROME_64_32_VERSION_CODE@\" " 120 "monochrome_64_version_code = \"@MONOCHROME_64_VERSION_CODE@\" " 121 "trichrome_64_32_version_code = \"@TRICHROME_64_32_VERSION_CODE@\" " 122 "trichrome_64_version_code = \"@TRICHROME_64_VERSION_CODE@\" ") 123 args_with_template = _ReplaceArgs(self._EXAMPLE_ANDROID_ARGS, 124 ['-t', new_template]) 125 new_args = _ReplaceArgs(args_with_template, ['-a', 'arm64']) 126 output = self._RunBuildOutput(get_new_args=lambda args: new_args) 127 contents = output['contents'] 128 129 self.assertRegex(contents, r'\bmonochrome_64_32_version_code = "\d+"\s') 130 self.assertRegex(contents, r'\bmonochrome_64_version_code = "\d+"\s') 131 self.assertRegex(contents, r'\btrichrome_64_32_version_code = "\d+"\s') 132 self.assertRegex(contents, r'\btrichrome_64_version_code = "\d+"\s') 133 134 def testBuildOutputAndroidArchVariantsX64(self): 135 """Assert 64-bit-specific version codes""" 136 new_template = ( 137 self._EXAMPLE_ANDROID_TEMPLATE + 138 "monochrome_64_32_version_code = \"@MONOCHROME_64_32_VERSION_CODE@\" " 139 "monochrome_64_version_code = \"@MONOCHROME_64_VERSION_CODE@\" " 140 "trichrome_64_32_version_code = \"@TRICHROME_64_32_VERSION_CODE@\" " 141 "trichrome_64_version_code = \"@TRICHROME_64_VERSION_CODE@\" ") 142 args_with_template = _ReplaceArgs(self._EXAMPLE_ANDROID_ARGS, 143 ['-t', new_template]) 144 new_args = _ReplaceArgs(args_with_template, ['-a', 'x64']) 145 output = self._RunBuildOutput(get_new_args=lambda args: new_args) 146 contents = output['contents'] 147 148 self.assertRegex(contents, r'\bmonochrome_64_32_version_code = "\d+"\s') 149 self.assertRegex(contents, r'\bmonochrome_64_version_code = "\d+"\s') 150 self.assertRegex(contents, r'\btrichrome_64_32_version_code = "\d+"\s') 151 self.assertRegex(contents, r'\btrichrome_64_version_code = "\d+"\s') 152 153 def testBuildOutputAndroidChromeArchInput(self): 154 """Assert it raises an exception when using an invalid architecture input""" 155 new_args = _ReplaceArgs(self._EXAMPLE_ANDROID_ARGS, ['-a', 'foobar']) 156 # Mock sys.stderr because argparse will print to stderr when we pass 157 # the invalid '-a' value. 158 with self.assertRaises(SystemExit) as cm, mock.patch('sys.stderr'): 159 self._RunBuildOutput(get_new_args=lambda args: new_args) 160 161 self.assertEqual(cm.exception.code, 2) 162 163 def testSetExecutable(self): 164 """Assert that -x sets executable on POSIX and is harmless on Windows.""" 165 with tempfile.TemporaryDirectory() as tmpdir: 166 in_file = os.path.join(tmpdir, "in") 167 out_file = os.path.join(tmpdir, "out") 168 with open(in_file, "w") as f: 169 f.write("") 170 self.assertEqual(version.main(['-i', in_file, '-o', out_file, '-x']), 0) 171 172 # Whether lstat(out_file).st_mode has the executable bits set is 173 # platform-specific. Therefore, test that out_file has the same 174 # permissions that in_file would have after chmod(in_file, 0o755). 175 # On Windows: both files will have 0o666. 176 # On POSIX: both files will have 0o755. 177 os.chmod(in_file, 0o755) # On Windows, this sets in_file to 0o666. 178 self.assertEqual(os.lstat(in_file).st_mode, os.lstat(out_file).st_mode) 179 180 181if __name__ == '__main__': 182 unittest.main() 183