1import unittest
2import os
3import sys
4import re
5import utils
6import subprocess
7
8TOPDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
9check_py = os.path.join(TOPDIR, "check_standards.py")
10sys.path.insert(0, TOPDIR)
11try:
12    import check_standards
13finally:
14    del sys.path[0]
15
16
17class Tests(unittest.TestCase):
18
19    def test_do_not_commit(self):
20        """Test _check_do_not_commit function"""
21        errors = []
22        check_standards._check_do_not_commit("", 'foo', 0, errors)
23        self.assertEqual(len(errors), 0)
24        check_standards._check_do_not_commit("DO NOT COMMIT", 'foo', 0, errors)
25        self.assertEqual(errors,
26                         ['foo:1: Line contains the string "DO NOT COMMIT"'])
27
28    def test_get_file(self):
29        """Test get_file function"""
30        with utils.TempDir() as tmpdir:
31            fname = os.path.join(tmpdir, 'foo')
32            utils.write_file(fname, 'foobar')
33            fh, fn = check_standards.get_file(fname)
34            self.assertEqual(fn, fname)
35            self.assertEqual(fh.read(), 'foobar')
36
37    def test_file_matches_re(self):
38        """Test file_matches_re function"""
39        excludes = [re.compile('foo')]
40        self.assertFalse(check_standards.file_matches_re("bar", excludes))
41        self.assertFalse(check_standards.file_matches_re("bar", []))
42        self.assertTrue(check_standards.file_matches_re("foobar", excludes))
43
44    def test_get_all_files(self):
45        """Test get_all_files function"""
46        with utils.RunInTempDir():
47            for subdir in ('.sconf_temp', os.path.join('build', 'include'),
48                           'ok'):
49                os.makedirs(subdir)
50                utils.write_file(os.path.join(subdir, "foo"), "")
51            for f in ('.foo', 'foo', 'bar'):
52                utils.write_file(f, "")
53            fs = sorted(check_standards.get_all_files())
54            self.assertEqual(fs, ['./bar', './foo', './ok/foo'])
55
56    def test_complete(self):
57        """Test simple complete run of check_standards script"""
58        with utils.TempDir() as tmpdir:
59            imp_info = os.path.join(tmpdir, ".imp_info.py")
60            utils.write_file(imp_info, '{\n  "name": "IMP.test"\n}\n')
61            fname = os.path.join(tmpdir, "test.py")
62            utils.write_file(fname, "# test file\n")
63            p = subprocess.Popen([check_py], cwd=tmpdir)
64            stdout, stderr = p.communicate()
65            self.assertEqual(p.returncode, 0)
66
67    def test_check_python_file_bad_indentation(self):
68        """Test check_python_file() with bad indentation"""
69        with utils.TempDir() as tmpdir:
70            fname = os.path.join(tmpdir, "test.py")
71            utils.write_file(fname, "def foo():\n  pass\n")
72            errors = []
73            check_standards.check_python_file(fname, errors)
74            self.assertEqual(len(errors), 1)
75            self.assertTrue("please run through" in errors[0])
76
77    def test_check_python_file_temp_test(self):
78        """Test check_python_file() with temp test marker"""
79        with utils.TempDir() as tmpdir:
80            fname = os.path.join(tmpdir, "test.py")
81            utils.write_file(fname, "class MyTest:\n"
82                             "    def temp_hide_test_bar():\n        pass\n")
83            errors = []
84            check_standards.check_python_file(fname, errors)
85            self.assertEqual(len(errors), 1)
86            self.assertTrue(":2: Test case has the temp_hide_ prefix"
87                            in errors[0])
88
89    def test_check_python_file_incomp_merge(self):
90        """Test check_python_file() with incomplete merge"""
91        with utils.TempDir() as tmpdir:
92            fname = os.path.join(tmpdir, "test.py")
93            utils.write_file(fname, ">>>>>>> \n")
94            errors = []
95            check_standards.check_python_file(fname, errors)
96            self.assertEqual(len(errors), 2)
97            self.assertTrue("please run through" in errors[0])
98            self.assertTrue(":1: error: Incomplete merge found."
99                            in errors[1])
100
101    def test_check_python_file_duplicate_tests(self):
102        """Test check_python_file() with duplicate tests"""
103        with utils.TempDir() as tmpdir:
104            fname = os.path.join(tmpdir, "test.py")
105            utils.write_file(fname, "class Tests:\n"
106                                    "    def test_xyz():\n        pass\n"
107                                    "    def test_xyz():\n        pass\n")
108            errors = []
109            check_standards.check_python_file(fname, errors)
110            self.assertEqual(len(errors), 1)
111            self.assertTrue(":4: Test case has multiple tests with "
112                            "the same name test_xyz" in errors[0])
113
114    def test_check_example_no_doxygen(self):
115        """Test Python example with missing doxygen comments"""
116        with utils.TempDir() as tmpdir:
117            os.mkdir(os.path.join(tmpdir, 'examples'))
118            fname = os.path.join(tmpdir, "examples", "my_example.py")
119            utils.write_file(fname, "x = 42\n")
120            errors = []
121            check_standards.check_python_file(fname, errors)
122            self.assertEqual(len(errors), 2)
123            self.assertTrue(":1: Example does not have doxygen comments "
124                            "at start" in errors[0])
125            self.assertTrue(":1: Example \\example marker in first line"
126                            in errors[1])
127
128    def test_check_example_bad_import(self):
129        """Test Python example with bad imports"""
130        with utils.TempDir() as tmpdir:
131            os.mkdir(os.path.join(tmpdir, 'examples'))
132            fname = os.path.join(tmpdir, "examples", "my_example.py")
133            utils.write_file(fname, """## \\example my_example.py
134from foo import bar
135import bar as baz
136""")
137            errors = []
138            check_standards.check_python_file(fname, errors)
139            self.assertEqual(len(errors), 2)
140            self.assertTrue(":2: Examples should not use import from as "
141                            "that confuses doxygen" in errors[0])
142            self.assertTrue(":3: Examples should not rename types on import"
143                            in errors[1])
144
145    def test_check_c_file_incomp_merge(self):
146        """Test check_c_file() with incomplete merge"""
147        with utils.TempDir() as tmpdir:
148            imp_info = os.path.join(tmpdir, ".imp_info.py")
149            utils.write_file(imp_info, '{\n  "name": "IMP.test"\n}\n')
150            fname = os.path.join(tmpdir, "test.cpp")
151            utils.write_file(fname, ">>>>>>> \n")
152            errors = []
153            check_standards.check_c_file(fname, errors)
154            self.assertEqual(len(errors), 1)
155            self.assertTrue(":1: error: Incomplete merge found."
156                            in errors[0])
157
158    def test_check_c_file_bad_define(self):
159        """Test check_c_file() with bad #defines"""
160        for ext in ('.cpp', '.h'):
161            with utils.TempDir() as tmpdir:
162                imp_info = os.path.join(tmpdir, ".imp_info.py")
163                utils.write_file(imp_info, '{\n  "name": "IMP.test"\n}\n')
164                fname = os.path.join(tmpdir, "test" + ext)
165                utils.write_file(fname,
166                                 "#define FOO BAR\n#define IMP_FOO BAR\n"
167                                 "#undef FOO\n"
168                                 "#define BAZ BAR\n"
169                                 "#define IMPTEST_FOO BAR\n"
170                                 "#define EIGEN_YES_I_KNOW_SPARSE_"
171                                 "MODULE_IS_NOT_STABLE_YET BAR\n")
172                errors = []
173                check_standards.check_c_file(fname, errors)
174                if ext == '.h':
175                    self.assertEqual(len(errors), 1)
176                    self.assertTrue(":4: error: Preprocessor symbols must "
177                                    "start with IMP_ or IMPTEST" in errors[0])
178                else:
179                    self.assertEqual(len(errors), 0)
180
181    def test_check_c_file_leading_blanks(self):
182        """Test check_c_file() with leading blank lines"""
183        with utils.TempDir() as tmpdir:
184            imp_info = os.path.join(tmpdir, ".imp_info.py")
185            utils.write_file(imp_info, '{\n  "name": "IMP.test"\n}\n')
186            fname = os.path.join(tmpdir, "test.cpp")
187            utils.write_file(fname, "\nint x;\n")
188            errors = []
189            check_standards.check_c_file(fname, errors)
190            self.assertEqual(len(errors), 1)
191            self.assertTrue(":1: File has leading blank line(s)" in errors[0])
192
193    def test_check_c_file_missing_file(self):
194        """Test check_c_file() with missing \\file marker"""
195        for subdir in ('include', 'internal'):
196            with utils.TempDir() as tmpdir:
197                imp_info = os.path.join(tmpdir, ".imp_info.py")
198                utils.write_file(imp_info, '{\n  "name": "IMP.test"\n}\n')
199                os.mkdir(os.path.join(tmpdir, subdir))
200                fname = os.path.join(tmpdir, subdir, "test.h")
201                utils.write_file(fname, "int x;\n")
202                errors = []
203                check_standards.check_c_file(fname, errors)
204                if subdir == 'include':
205                    self.assertEqual(len(errors), 1)
206                    self.assertTrue(":2: Exported header must have a "
207                                    "line \\file IMP/test/test.h" in errors[0])
208                else:
209                    self.assertEqual(len(errors), 0)
210
211    def test_check_c_file_cpp_ok(self):
212        """Test check_c_file() with ok cpp file"""
213        with utils.TempDir() as tmpdir:
214            imp_info = os.path.join(tmpdir, ".imp_info.py")
215            utils.write_file(imp_info, '{\n  "name": "IMP.test"\n}\n')
216            fname = os.path.join(tmpdir, "test.cpp")
217            utils.write_file(fname, "int x;\n")
218            errors = []
219            check_standards.check_c_file(fname, errors)
220            self.assertEqual(len(errors), 0)
221
222    def test_check_c_file_header_ok(self):
223        """Test check_c_file() with ok header file"""
224        with utils.TempDir() as tmpdir:
225            os.makedirs(os.path.join(tmpdir, 'IMP', 'test', 'include'))
226            imp_info = os.path.join(tmpdir, ".imp_info.py")
227            utils.write_file(imp_info, '{\n  "name": "IMP.test"\n}\n')
228            fname = os.path.join(tmpdir, "IMP", "test", "include", "foo.h")
229            utils.write_file(fname, "\\file IMP/test/include/foo.h'")
230            errors = []
231            check_standards.check_c_file(fname, errors)
232            self.assertEqual(len(errors), 0)
233
234
235if __name__ == '__main__':
236    unittest.main()
237