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