| OLD | NEW |
| (Empty) |
| 1 # Copyright (c) 2016 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import os | |
| 6 import re | |
| 7 import sys | |
| 8 import unittest | |
| 9 import PRESUBMIT | |
| 10 | |
| 11 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| 12 from PRESUBMIT_test_mocks import MockOutputApi, MockChange | |
| 13 | |
| 14 class MockInputApi(object): | |
| 15 """ Mocked input api for unit testing of presubmit. | |
| 16 This lets us mock things like file system operations and changed files. | |
| 17 """ | |
| 18 def __init__(self): | |
| 19 self.re = re | |
| 20 self.os_path = os.path | |
| 21 self.files = [] | |
| 22 self.is_committing = False | |
| 23 | |
| 24 def AffectedFiles(self): | |
| 25 return self.files | |
| 26 | |
| 27 def AffectedSourceFiles(self): | |
| 28 return self.files | |
| 29 | |
| 30 def ReadFile(self, f): | |
| 31 """ Returns the mock contents of f if they've been defined. | |
| 32 """ | |
| 33 for api_file in self.files: | |
| 34 if api_file.LocalPath() == f: | |
| 35 return api_file.NewContents() | |
| 36 | |
| 37 | |
| 38 class MockFile(object): | |
| 39 """Mock file object so that presubmit can act invoke file system operations. | |
| 40 """ | |
| 41 def __init__(self, local_path, new_contents): | |
| 42 self._local_path = local_path | |
| 43 self._new_contents = new_contents | |
| 44 self._changed_contents = ([(i + 1, l) for i, l in enumerate(new_contents)]) | |
| 45 | |
| 46 def ChangedContents(self): | |
| 47 return self._changed_contents | |
| 48 | |
| 49 def NewContents(self): | |
| 50 return self._new_contents | |
| 51 | |
| 52 def LocalPath(self): | |
| 53 return self._local_path | |
| 54 | |
| 55 def AbsoluteLocalPath(self): | |
| 56 return self._local_path | |
| 57 # Format string used as the contents of a mock sync.proto in order to | |
| 58 # test presubmit parsing of EntitySpecifics definition in that file. | |
| 59 MOCK_PROTOFILE_CONTENTS = ('\n' | |
| 60 'message EntitySpecifics {\n' | |
| 61 '//comment\n' | |
| 62 '\n' | |
| 63 'optional AutofillSpecifics autofill = 123;\n' | |
| 64 'optional AppSpecifics app = 456;\n' | |
| 65 'optional AppSettingSpecifics app_setting = 789;\n' | |
| 66 '//comment\n' | |
| 67 '}\n') | |
| 68 | |
| 69 | |
| 70 # Format string used as the contents of a mock model_type.cc | |
| 71 # in order to test presubmit parsing of the ModelTypeInfoMap in that file. | |
| 72 MOCK_MODELTYPE_CONTENTS =('\n' | |
| 73 'const ModelTypeInfo kModelTypeInfoMap[] = {\n' | |
| 74 '{APP_SETTINGS, "APP_SETTING", "app_settings", "App settings",\n' | |
| 75 'sync_pb::EntitySpecifics::kAppSettingFieldNumber, 13},\n' | |
| 76 '%s\n' | |
| 77 '};\n') | |
| 78 | |
| 79 | |
| 80 class ModelTypeInfoChangeTest(unittest.TestCase): | |
| 81 """Unit testing class that contains tests for sync/PRESUBMIT.py. | |
| 82 """ | |
| 83 def test_ValidChangeMultiLine(self): | |
| 84 results = self._testChange('{APPS, "APP", "apps", "Apps",\n' | |
| 85 'sync_pb::EntitySpecifics::kAppFieldNumber, 12},') | |
| 86 self.assertEqual(0, len(results)) | |
| 87 | |
| 88 def testValidChangeToleratesPluralization(self): | |
| 89 results = self._testChange('{APPS, "APP", "apps", "App",\n' | |
| 90 'sync_pb::EntitySpecifics::kAppFieldNumber, 12},') | |
| 91 self.assertEqual(0, len(results)) | |
| 92 | |
| 93 def testValidChangeGrandfatheredEntry(self): | |
| 94 results = self._testChange('{PROXY_TABS, "", "", "Tabs", -1, 25},') | |
| 95 self.assertEqual(0, len(results)) | |
| 96 | |
| 97 def testInvalidChangeMismatchedNotificationType(self): | |
| 98 results = self._testChange('{AUTOFILL, "AUTOFILL_WRONG", "autofill",\n' | |
| 99 '"Autofill",sync_pb::EntitySpecifics::kAutofillFieldNumber, 6},') | |
| 100 self.assertEqual(1, len(results)) | |
| 101 self.assertTrue('notification type' in results[0].message) | |
| 102 | |
| 103 def testInvalidChangeInconsistentModelType(self): | |
| 104 results = self._testChange('{AUTOFILL, "AUTOFILL", "autofill",\n' | |
| 105 '"Autofill Extra",sync_pb::EntitySpecifics::kAutofillFieldNumber, 6},') | |
| 106 self.assertEqual(1, len(results)) | |
| 107 self.assertTrue('model type string' in results[0].message) | |
| 108 | |
| 109 def testInvalidChangeNotTitleCased(self): | |
| 110 results = self._testChange('{AUTOFILL, "AUTOFILL", "autofill",\n' | |
| 111 '"autofill",sync_pb::EntitySpecifics::kAutofillFieldNumber, 6},') | |
| 112 self.assertEqual(1, len(results)) | |
| 113 self.assertTrue('title' in results[0].message) | |
| 114 | |
| 115 def testInvalidChangeInconsistentRootTag(self): | |
| 116 results = self._testChange('{AUTOFILL, "AUTOFILL", "autofill root",\n' | |
| 117 '"Autofill",sync_pb::EntitySpecifics::kAutofillFieldNumber, 6},') | |
| 118 self.assertEqual(1, len(results)) | |
| 119 self.assertTrue('root tag' in results[0].message) | |
| 120 | |
| 121 def testInvalidChangeDuplicatedValues(self): | |
| 122 results = self._testChange('{APP_SETTINGS, "APP_SETTING",\n' | |
| 123 '"app_settings", "App settings",\n' | |
| 124 'sync_pb::EntitySpecifics::kAppSettingFieldNumber, 13},\n') | |
| 125 self.assertEqual(6, len(results)) | |
| 126 self.assertTrue('APP_SETTINGS' in results[0].message) | |
| 127 | |
| 128 def _testChange(self, modeltype_literal): | |
| 129 mock_input_api = MockInputApi() | |
| 130 mock_input_api.files = [ | |
| 131 MockFile(os.path.abspath('./protocol/sync.proto'), | |
| 132 MOCK_PROTOFILE_CONTENTS), | |
| 133 MockFile(os.path.abspath('./syncable/model_type.cc'), | |
| 134 MOCK_MODELTYPE_CONTENTS % (modeltype_literal)) | |
| 135 ] | |
| 136 | |
| 137 return PRESUBMIT.CheckChangeOnCommit(mock_input_api, MockOutputApi()) | |
| 138 if __name__ == '__main__': | |
| 139 unittest.main() | |
| OLD | NEW |