summaryrefslogtreecommitdiffstats
path: root/PRESUBMIT_test.py
diff options
context:
space:
mode:
authoryoz@chromium.org <yoz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-03 08:44:47 +0000
committeryoz@chromium.org <yoz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-03 08:44:47 +0000
commit99171a94995b46692a7008a9f2f0548e4b38d29f (patch)
treec439e6403f5c1c787f9775542605c4cea24ce77e /PRESUBMIT_test.py
parent21075b5dc4f91266175d92b46c004c24bf69f73e (diff)
downloadchromium_src-99171a94995b46692a7008a9f2f0548e4b38d29f.zip
chromium_src-99171a94995b46692a7008a9f2f0548e4b38d29f.tar.gz
chromium_src-99171a94995b46692a7008a9f2f0548e4b38d29f.tar.bz2
Add global presubmit that JSON and IDL files can be parsed.
Sometimes, changes to JSON/IDL files make them invalid. It's easier to check these at presubmit time than discovering they can't be parsed at runtime. This just moves the check from chrome/common/extensions/api to top-level. This presubmit check excludes files in test/data directories. BUG=366395 Review URL: https://codereview.chromium.org/239283008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274432 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'PRESUBMIT_test.py')
-rwxr-xr-xPRESUBMIT_test.py216
1 files changed, 216 insertions, 0 deletions
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index 3bebc67..5a682a1 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -3,23 +3,43 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import glob
+import json
import os
import re
+import subprocess
+import sys
import unittest
import PRESUBMIT
+_TEST_DATA_DIR = 'base/test/data/presubmit'
+
+
class MockInputApi(object):
def __init__(self):
+ self.json = json
self.re = re
self.os_path = os.path
+ self.python_executable = sys.executable
+ self.subprocess = subprocess
self.files = []
self.is_committing = False
def AffectedFiles(self):
return self.files
+ def PresubmitLocalPath(self):
+ return os.path.dirname(__file__)
+
+ def ReadFile(self, filename, mode='rU'):
+ for file_ in self.files:
+ if file_.LocalPath() == filename:
+ return '\n'.join(file_.NewContents())
+ # Otherwise, file is not in our mock API.
+ raise IOError, "No such file or directory: '%s'" % filename
+
class MockOutputApi(object):
class PresubmitResult(object):
@@ -431,5 +451,201 @@ class CheckAddedDepsHaveTetsApprovalsTest(unittest.TestCase):
self.assertEqual(expected, files_to_check);
+class JSONParsingTest(unittest.TestCase):
+ def testSuccess(self):
+ input_api = MockInputApi()
+ filename = 'valid_json.json'
+ contents = ['// This is a comment.',
+ '{',
+ ' "key1": ["value1", "value2"],',
+ ' "key2": 3 // This is an inline comment.',
+ '}'
+ ]
+ input_api.files = [MockFile(filename, contents)]
+ self.assertEqual(None,
+ PRESUBMIT._GetJSONParseError(input_api, filename))
+
+ def testFailure(self):
+ input_api = MockInputApi()
+ test_data = [
+ ('invalid_json_1.json',
+ ['{ x }'],
+ 'Expecting property name: line 1 column 2 (char 2)'),
+ ('invalid_json_2.json',
+ ['// Hello world!',
+ '{ "hello": "world }'],
+ 'Unterminated string starting at: line 2 column 12 (char 12)'),
+ ('invalid_json_3.json',
+ ['{ "a": "b", "c": "d", }'],
+ 'Expecting property name: line 1 column 22 (char 22)'),
+ ('invalid_json_4.json',
+ ['{ "a": "b" "c": "d" }'],
+ 'Expecting , delimiter: line 1 column 11 (char 11)'),
+ ]
+
+ input_api.files = [MockFile(filename, contents)
+ for (filename, contents, _) in test_data]
+
+ for (filename, _, expected_error) in test_data:
+ actual_error = PRESUBMIT._GetJSONParseError(input_api, filename)
+ self.assertEqual(expected_error, str(actual_error))
+
+ def testNoEatComments(self):
+ input_api = MockInputApi()
+ file_with_comments = 'file_with_comments.json'
+ contents_with_comments = ['// This is a comment.',
+ '{',
+ ' "key1": ["value1", "value2"],',
+ ' "key2": 3 // This is an inline comment.',
+ '}'
+ ]
+ file_without_comments = 'file_without_comments.json'
+ contents_without_comments = ['{',
+ ' "key1": ["value1", "value2"],',
+ ' "key2": 3',
+ '}'
+ ]
+ input_api.files = [MockFile(file_with_comments, contents_with_comments),
+ MockFile(file_without_comments,
+ contents_without_comments)]
+
+ self.assertEqual('No JSON object could be decoded',
+ str(PRESUBMIT._GetJSONParseError(input_api,
+ file_with_comments,
+ eat_comments=False)))
+ self.assertEqual(None,
+ PRESUBMIT._GetJSONParseError(input_api,
+ file_without_comments,
+ eat_comments=False))
+
+
+class IDLParsingTest(unittest.TestCase):
+ def testSuccess(self):
+ input_api = MockInputApi()
+ filename = 'valid_idl_basics.idl'
+ contents = ['// Tests a valid IDL file.',
+ 'namespace idl_basics {',
+ ' enum EnumType {',
+ ' name1,',
+ ' name2',
+ ' };',
+ '',
+ ' dictionary MyType1 {',
+ ' DOMString a;',
+ ' };',
+ '',
+ ' callback Callback1 = void();',
+ ' callback Callback2 = void(long x);',
+ ' callback Callback3 = void(MyType1 arg);',
+ ' callback Callback4 = void(EnumType type);',
+ '',
+ ' interface Functions {',
+ ' static void function1();',
+ ' static void function2(long x);',
+ ' static void function3(MyType1 arg);',
+ ' static void function4(Callback1 cb);',
+ ' static void function5(Callback2 cb);',
+ ' static void function6(Callback3 cb);',
+ ' static void function7(Callback4 cb);',
+ ' };',
+ '',
+ ' interface Events {',
+ ' static void onFoo1();',
+ ' static void onFoo2(long x);',
+ ' static void onFoo2(MyType1 arg);',
+ ' static void onFoo3(EnumType type);',
+ ' };',
+ '};'
+ ]
+ input_api.files = [MockFile(filename, contents)]
+ self.assertEqual(None,
+ PRESUBMIT._GetIDLParseError(input_api, filename))
+
+ def testFailure(self):
+ input_api = MockInputApi()
+ test_data = [
+ ('invalid_idl_1.idl',
+ ['//',
+ 'namespace test {',
+ ' dictionary {',
+ ' DOMString s;',
+ ' };',
+ '};'],
+ 'Unexpected "{" after keyword "dictionary".\n'),
+ # TODO(yoz): Disabled because it causes the IDL parser to hang.
+ # See crbug.com/363830.
+ # ('invalid_idl_2.idl',
+ # (['namespace test {',
+ # ' dictionary MissingSemicolon {',
+ # ' DOMString a',
+ # ' DOMString b;',
+ # ' };',
+ # '};'],
+ # 'Unexpected symbol DOMString after symbol a.'),
+ ('invalid_idl_3.idl',
+ ['//',
+ 'namespace test {',
+ ' enum MissingComma {',
+ ' name1',
+ ' name2',
+ ' };',
+ '};'],
+ 'Unexpected symbol name2 after symbol name1.'),
+ ('invalid_idl_4.idl',
+ ['//',
+ 'namespace test {',
+ ' enum TrailingComma {',
+ ' name1,',
+ ' name2,',
+ ' };',
+ '};'],
+ 'Trailing comma in block.'),
+ ('invalid_idl_5.idl',
+ ['//',
+ 'namespace test {',
+ ' callback Callback1 = void(;',
+ '};'],
+ 'Unexpected ";" after "(".'),
+ ('invalid_idl_6.idl',
+ ['//',
+ 'namespace test {',
+ ' callback Callback1 = void(long );',
+ '};'],
+ 'Unexpected ")" after symbol long.'),
+ ('invalid_idl_7.idl',
+ ['//',
+ 'namespace test {',
+ ' interace Events {',
+ ' static void onFoo1();',
+ ' };',
+ '};'],
+ 'Unexpected symbol Events after symbol interace.'),
+ ('invalid_idl_8.idl',
+ ['//',
+ 'namespace test {',
+ ' interface NotEvent {',
+ ' static void onFoo1();',
+ ' };',
+ '};'],
+ 'Did not process Interface Interface(NotEvent)'),
+ ('invalid_idl_9.idl',
+ ['//',
+ 'namespace test {',
+ ' interface {',
+ ' static void function1();',
+ ' };',
+ '};'],
+ 'Interface missing name.'),
+ ]
+
+ input_api.files = [MockFile(filename, contents)
+ for (filename, contents, _) in test_data]
+
+ for (filename, _, expected_error) in test_data:
+ actual_error = PRESUBMIT._GetIDLParseError(input_api, filename)
+ self.assertTrue(expected_error in str(actual_error),
+ "'%s' not found in '%s'" % (expected_error, actual_error))
+
+
if __name__ == '__main__':
unittest.main()