Clean up histogram'd media enum max values.

This adds a PRESUBMIT test to src/media/ which enforces the following when using UMA_HISTOGRAM_ENUMERATION:
- The max enum value should be suffixed with 'MAX' or 'Max' (and it should be equal to the largest valid entry ever logged).
- One should be added to that max value when used in the UMA_HISTOGRAM_ENUMERATION macro.

To handle past misuses of UMA_HISTOGRAM_ENUMERATION for non-enums a comment of '// IGNORE_PRESUBMIT_UMA_MAX' was added to silence the presubmit check.

BUG=165553
TBR=danakj

Review URL: https://codereview.chromium.org/148553003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@254209 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/media/PRESUBMIT_test.py b/media/PRESUBMIT_test.py
new file mode 100644
index 0000000..f537a6d
--- /dev/null
+++ b/media/PRESUBMIT_test.py
@@ -0,0 +1,150 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import os
+import re
+import unittest
+
+import PRESUBMIT
+
+class MockInputApi(object):
+  def __init__(self):
+    self.re = re
+    self.os_path = os.path
+    self.files = []
+    self.is_committing = False
+
+  def AffectedFiles(self):
+    return self.files
+
+  def AffectedSourceFiles(self, fn):
+    # we'll just pretend everything is a source file for the sake of simplicity
+    return self.files
+
+  def ReadFile(self, f):
+    return f.NewContents()
+
+
+class MockOutputApi(object):
+  class PresubmitResult(object):
+    def __init__(self, message, items=None, long_text=''):
+      self.message = message
+      self.items = items
+      self.long_text = long_text
+
+  class PresubmitError(PresubmitResult):
+    def __init__(self, message, items, long_text=''):
+      MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
+      self.type = 'error'
+
+  class PresubmitPromptWarning(PresubmitResult):
+    def __init__(self, message, items, long_text=''):
+      MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
+      self.type = 'warning'
+
+  class PresubmitNotifyResult(PresubmitResult):
+    def __init__(self, message, items, long_text=''):
+      MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
+      self.type = 'notify'
+
+  class PresubmitPromptOrNotify(PresubmitResult):
+    def __init__(self, message, items, long_text=''):
+      MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
+      self.type = 'promptOrNotify'
+
+
+class MockFile(object):
+  def __init__(self, local_path, new_contents):
+    self._local_path = local_path
+    self._new_contents = new_contents
+    self._changed_contents = [(i + 1, l) for i, l in enumerate(new_contents)]
+
+  def ChangedContents(self):
+    return self._changed_contents
+
+  def NewContents(self):
+    return self._new_contents
+
+  def LocalPath(self):
+    return self._local_path
+
+
+class MockChange(object):
+  def __init__(self, changed_files):
+    self._changed_files = changed_files
+
+  def LocalPaths(self):
+    return self._changed_files
+
+
+class HistogramOffByOneTest(unittest.TestCase):
+
+  # Take an input and make sure the problems found equals the expectation.
+  def simpleCheck(self, contents, expected_errors):
+    input_api = MockInputApi()
+    input_api.files.append(MockFile('test.cc', contents))
+    results = PRESUBMIT._CheckForHistogramOffByOne(input_api, MockOutputApi())
+    if expected_errors:
+      self.assertEqual(1, len(results))
+      self.assertEqual(expected_errors, len(results[0].items))
+    else:
+      self.assertEqual(0, len(results))
+
+  def testValid(self):
+    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax + 1);', 0)
+
+  def testValidComments(self):
+    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", /*...*/ kFoo, /*...*/'
+                     'kFooMax + 1);', 0)
+
+  def testValidMultiLine(self):
+    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",\n'
+                     '                          kFoo,\n'
+                     '                          kFooMax + 1);', 0)
+
+  def testValidMultiLineComments(self):
+    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",  // This is the name\n'
+                     '                          kFoo,  /* The value */\n'
+                     '                          kFooMax + 1 /* The max */ );',
+                     0)
+
+  def testNoPlusOne(self):
+    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax);', 1)
+
+  def testInvalidWithIgnore(self):
+    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax); '
+                     '// PRESUBMIT_IGNORE_UMA_MAX', 0)
+
+  def testNoMax(self):
+    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo + 1);', 1)
+
+  def testNoMaxNoPlusOne(self):
+    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo);', 1)
+
+  def testMultipleErrors(self):
+    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo);\n'
+                     'printf("hello, world!");\n'
+                     'UMA_HISTOGRAM_ENUMERATION("test", kBar, kBarMax);', 2)
+
+  def testValidAndInvalid(self):
+    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo);\n'
+                     'UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax + 1);'
+                     'UMA_HISTOGRAM_ENUMERATION("test", kBar, kBarMax);', 2)
+
+  def testInvalidMultiLine(self):
+    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",\n'
+                     '                          kFoo,\n'
+                     '                          kFooMax + 2);', 1)
+
+  def testInvalidComments(self):
+    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", /*...*/, val, /*...*/,'
+                     'Max);\n', 1)
+
+  def testInvalidMultiLineComments(self):
+    self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",  // This is the name\n'
+                     '                          kFoo,  /* The value */\n'
+                     '                          kFooMax + 2 /* The max */ );',
+                     1)
+
+if __name__ == '__main__':
+  unittest.main()