1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import os
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import re
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import unittest
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import PRESUBMIT
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class MockInputApi(object):
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def __init__(self):
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.re = re
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.os_path = os.path
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.files = []
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.is_committing = False
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def AffectedFiles(self):
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return self.files
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def AffectedSourceFiles(self, fn):
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # we'll just pretend everything is a source file for the sake of simplicity
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return self.files
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def ReadFile(self, f):
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return f.NewContents()
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class MockOutputApi(object):
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  class PresubmitResult(object):
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    def __init__(self, message, items=None, long_text=''):
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.message = message
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.items = items
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.long_text = long_text
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  class PresubmitError(PresubmitResult):
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    def __init__(self, message, items, long_text=''):
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.type = 'error'
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  class PresubmitPromptWarning(PresubmitResult):
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    def __init__(self, message, items, long_text=''):
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.type = 'warning'
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  class PresubmitNotifyResult(PresubmitResult):
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    def __init__(self, message, items, long_text=''):
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.type = 'notify'
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  class PresubmitPromptOrNotify(PresubmitResult):
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    def __init__(self, message, items, long_text=''):
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.type = 'promptOrNotify'
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class MockFile(object):
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def __init__(self, local_path, new_contents):
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._local_path = local_path
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._new_contents = new_contents
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._changed_contents = [(i + 1, l) for i, l in enumerate(new_contents)]
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def ChangedContents(self):
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return self._changed_contents
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def NewContents(self):
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return self._new_contents
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def LocalPath(self):
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return self._local_path
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class MockChange(object):
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def __init__(self, changed_files):
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._changed_files = changed_files
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def LocalPaths(self):
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return self._changed_files
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class HistogramOffByOneTest(unittest.TestCase):
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  # Take an input and make sure the problems found equals the expectation.
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def simpleCheck(self, contents, expected_errors):
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    input_api = MockInputApi()
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    input_api.files.append(MockFile('test.cc', contents))
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    results = PRESUBMIT._CheckForHistogramOffByOne(input_api, MockOutputApi())
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if expected_errors:
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.assertEqual(1, len(results))
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.assertEqual(expected_errors, len(results[0].items))
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    else:
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.assertEqual(0, len(results))
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testValid(self):
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax + 1);', 0)
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testValidComments(self):
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", /*...*/ kFoo, /*...*/'
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     'kFooMax + 1);', 0)
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testValidMultiLine(self):
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",\n'
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     '                          kFoo,\n'
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     '                          kFooMax + 1);', 0)
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testValidMultiLineComments(self):
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",  // This is the name\n'
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     '                          kFoo,  /* The value */\n'
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     '                          kFooMax + 1 /* The max */ );',
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     0)
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testNoPlusOne(self):
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax);', 1)
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testInvalidWithIgnore(self):
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax); '
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     '// PRESUBMIT_IGNORE_UMA_MAX', 0)
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testNoMax(self):
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo + 1);', 1)
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testNoMaxNoPlusOne(self):
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo);', 1)
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testMultipleErrors(self):
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo);\n'
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     'printf("hello, world!");\n'
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     'UMA_HISTOGRAM_ENUMERATION("test", kBar, kBarMax);', 2)
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testValidAndInvalid(self):
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo);\n'
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     'UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax + 1);'
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     'UMA_HISTOGRAM_ENUMERATION("test", kBar, kBarMax);', 2)
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testInvalidMultiLine(self):
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",\n'
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     '                          kFoo,\n'
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     '                          kFooMax + 2);', 1)
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testInvalidComments(self):
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", /*...*/, val, /*...*/,'
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     'Max);\n', 1)
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testInvalidMultiLineComments(self):
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",  // This is the name\n'
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     '                          kFoo,  /* The value */\n'
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     '                          kFooMax + 2 /* The max */ );',
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     1)
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)if __name__ == '__main__':
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  unittest.main()
151