1 # Copyright (C) 2010 Chris Jerdonek (cjerdonek (at] webkit.org) 2 # 3 # Redistribution and use in source and binary forms, with or without 4 # modification, are permitted provided that the following conditions 5 # are met: 6 # 1. Redistributions of source code must retain the above copyright 7 # notice, this list of conditions and the following disclaimer. 8 # 2. Redistributions in binary form must reproduce the above copyright 9 # notice, this list of conditions and the following disclaimer in the 10 # documentation and/or other materials provided with the distribution. 11 # 12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 13 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 16 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 23 """Unit tests for parser.py.""" 24 25 import unittest 26 27 from webkitpy.common.system.logtesting import LoggingTestCase 28 from webkitpy.style.optparser import ArgumentParser 29 from webkitpy.style.optparser import ArgumentPrinter 30 from webkitpy.style.optparser import CommandOptionValues as ProcessorOptions 31 from webkitpy.style.optparser import DefaultCommandOptionValues 32 33 34 class ArgumentPrinterTest(unittest.TestCase): 35 36 """Tests the ArgumentPrinter class.""" 37 38 _printer = ArgumentPrinter() 39 40 def _create_options(self, 41 output_format='emacs', 42 min_confidence=3, 43 filter_rules=[], 44 git_commit=None): 45 return ProcessorOptions(filter_rules=filter_rules, 46 git_commit=git_commit, 47 min_confidence=min_confidence, 48 output_format=output_format) 49 50 def test_to_flag_string(self): 51 options = self._create_options('vs7', 5, ['+foo', '-bar'], 'git') 52 self.assertEquals('--filter=+foo,-bar --git-commit=git ' 53 '--min-confidence=5 --output=vs7', 54 self._printer.to_flag_string(options)) 55 56 # This is to check that --filter and --git-commit do not 57 # show up when not user-specified. 58 options = self._create_options() 59 self.assertEquals('--min-confidence=3 --output=emacs', 60 self._printer.to_flag_string(options)) 61 62 63 class ArgumentParserTest(LoggingTestCase): 64 65 """Test the ArgumentParser class.""" 66 67 class _MockStdErr(object): 68 69 def write(self, message): 70 # We do not want the usage string or style categories 71 # to print during unit tests, so print nothing. 72 return 73 74 def _parse(self, args): 75 """Call a test parser.parse().""" 76 parser = self._create_parser() 77 return parser.parse(args) 78 79 def _create_defaults(self): 80 """Return a DefaultCommandOptionValues instance for testing.""" 81 base_filter_rules = ["-", "+whitespace"] 82 return DefaultCommandOptionValues(min_confidence=3, 83 output_format="vs7") 84 85 def _create_parser(self): 86 """Return an ArgumentParser instance for testing.""" 87 default_options = self._create_defaults() 88 89 all_categories = ["build" ,"whitespace"] 90 91 mock_stderr = self._MockStdErr() 92 93 return ArgumentParser(all_categories=all_categories, 94 base_filter_rules=[], 95 default_options=default_options, 96 mock_stderr=mock_stderr, 97 usage="test usage") 98 99 def test_parse_documentation(self): 100 parse = self._parse 101 102 # FIXME: Test both the printing of the usage string and the 103 # filter categories help. 104 105 # Request the usage string. 106 self.assertRaises(SystemExit, parse, ['--help']) 107 # Request default filter rules and available style categories. 108 self.assertRaises(SystemExit, parse, ['--filter=']) 109 110 def test_parse_bad_values(self): 111 parse = self._parse 112 113 # Pass an unsupported argument. 114 self.assertRaises(SystemExit, parse, ['--bad']) 115 self.assertLog(['ERROR: no such option: --bad\n']) 116 117 self.assertRaises(SystemExit, parse, ['--min-confidence=bad']) 118 self.assertLog(['ERROR: option --min-confidence: ' 119 "invalid integer value: 'bad'\n"]) 120 self.assertRaises(SystemExit, parse, ['--min-confidence=0']) 121 self.assertLog(['ERROR: option --min-confidence: invalid integer: 0: ' 122 'value must be between 1 and 5\n']) 123 self.assertRaises(SystemExit, parse, ['--min-confidence=6']) 124 self.assertLog(['ERROR: option --min-confidence: invalid integer: 6: ' 125 'value must be between 1 and 5\n']) 126 parse(['--min-confidence=1']) # works 127 parse(['--min-confidence=5']) # works 128 129 self.assertRaises(SystemExit, parse, ['--output=bad']) 130 self.assertLog(['ERROR: option --output-format: invalid choice: ' 131 "'bad' (choose from 'emacs', 'vs7')\n"]) 132 parse(['--output=vs7']) # works 133 134 # Pass a filter rule not beginning with + or -. 135 self.assertRaises(SystemExit, parse, ['--filter=build']) 136 self.assertLog(['ERROR: Invalid filter rule "build": ' 137 'every rule must start with + or -.\n']) 138 parse(['--filter=+build']) # works 139 140 def test_parse_default_arguments(self): 141 parse = self._parse 142 143 (files, options) = parse([]) 144 145 self.assertEquals(files, []) 146 147 self.assertEquals(options.filter_rules, []) 148 self.assertEquals(options.git_commit, None) 149 self.assertEquals(options.diff_files, False) 150 self.assertEquals(options.is_verbose, False) 151 self.assertEquals(options.min_confidence, 3) 152 self.assertEquals(options.output_format, 'vs7') 153 154 def test_parse_explicit_arguments(self): 155 parse = self._parse 156 157 # Pass non-default explicit values. 158 (files, options) = parse(['--min-confidence=4']) 159 self.assertEquals(options.min_confidence, 4) 160 (files, options) = parse(['--output=emacs']) 161 self.assertEquals(options.output_format, 'emacs') 162 (files, options) = parse(['-g', 'commit']) 163 self.assertEquals(options.git_commit, 'commit') 164 (files, options) = parse(['--git-commit=commit']) 165 self.assertEquals(options.git_commit, 'commit') 166 (files, options) = parse(['--git-diff=commit']) 167 self.assertEquals(options.git_commit, 'commit') 168 (files, options) = parse(['--verbose']) 169 self.assertEquals(options.is_verbose, True) 170 (files, options) = parse(['--diff-files', 'file.txt']) 171 self.assertEquals(options.diff_files, True) 172 173 # Pass user_rules. 174 (files, options) = parse(['--filter=+build,-whitespace']) 175 self.assertEquals(options.filter_rules, 176 ["+build", "-whitespace"]) 177 178 # Pass spurious white space in user rules. 179 (files, options) = parse(['--filter=+build, -whitespace']) 180 self.assertEquals(options.filter_rules, 181 ["+build", "-whitespace"]) 182 183 def test_parse_files(self): 184 parse = self._parse 185 186 (files, options) = parse(['foo.cpp']) 187 self.assertEquals(files, ['foo.cpp']) 188 189 # Pass multiple files. 190 (files, options) = parse(['--output=emacs', 'foo.cpp', 'bar.cpp']) 191 self.assertEquals(files, ['foo.cpp', 'bar.cpp']) 192 193 194 class CommandOptionValuesTest(unittest.TestCase): 195 196 """Tests CommandOptionValues class.""" 197 198 def test_init(self): 199 """Test __init__ constructor.""" 200 # Check default parameters. 201 options = ProcessorOptions() 202 self.assertEquals(options.filter_rules, []) 203 self.assertEquals(options.git_commit, None) 204 self.assertEquals(options.is_verbose, False) 205 self.assertEquals(options.min_confidence, 1) 206 self.assertEquals(options.output_format, "emacs") 207 208 # Check argument validation. 209 self.assertRaises(ValueError, ProcessorOptions, output_format="bad") 210 ProcessorOptions(output_format="emacs") # No ValueError: works 211 ProcessorOptions(output_format="vs7") # works 212 self.assertRaises(ValueError, ProcessorOptions, min_confidence=0) 213 self.assertRaises(ValueError, ProcessorOptions, min_confidence=6) 214 ProcessorOptions(min_confidence=1) # works 215 ProcessorOptions(min_confidence=5) # works 216 217 # Check attributes. 218 options = ProcessorOptions(filter_rules=["+"], 219 git_commit="commit", 220 is_verbose=True, 221 min_confidence=3, 222 output_format="vs7") 223 self.assertEquals(options.filter_rules, ["+"]) 224 self.assertEquals(options.git_commit, "commit") 225 self.assertEquals(options.is_verbose, True) 226 self.assertEquals(options.min_confidence, 3) 227 self.assertEquals(options.output_format, "vs7") 228 229 def test_eq(self): 230 """Test __eq__ equality function.""" 231 self.assertTrue(ProcessorOptions().__eq__(ProcessorOptions())) 232 233 # Also verify that a difference in any argument causes equality to fail. 234 235 # Explicitly create a ProcessorOptions instance with all default 236 # values. We do this to be sure we are assuming the right default 237 # values in our self.assertFalse() calls below. 238 options = ProcessorOptions(filter_rules=[], 239 git_commit=None, 240 is_verbose=False, 241 min_confidence=1, 242 output_format="emacs") 243 # Verify that we created options correctly. 244 self.assertTrue(options.__eq__(ProcessorOptions())) 245 246 self.assertFalse(options.__eq__(ProcessorOptions(filter_rules=["+"]))) 247 self.assertFalse(options.__eq__(ProcessorOptions(git_commit="commit"))) 248 self.assertFalse(options.__eq__(ProcessorOptions(is_verbose=True))) 249 self.assertFalse(options.__eq__(ProcessorOptions(min_confidence=2))) 250 self.assertFalse(options.__eq__(ProcessorOptions(output_format="vs7"))) 251 252 def test_ne(self): 253 """Test __ne__ inequality function.""" 254 # By default, __ne__ always returns true on different objects. 255 # Thus, just check the distinguishing case to verify that the 256 # code defines __ne__. 257 self.assertFalse(ProcessorOptions().__ne__(ProcessorOptions())) 258 259