| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/env python | |
| 2 # Copyright 2008 The Closure Linter Authors. All Rights Reserved. | |
| 3 # | |
| 4 # Licensed under the Apache License, Version 2.0 (the "License"); | |
| 5 # you may not use this file except in compliance with the License. | |
| 6 # You may obtain a copy of the License at | |
| 7 # | |
| 8 # http://www.apache.org/licenses/LICENSE-2.0 | |
| 9 # | |
| 10 # Unless required by applicable law or agreed to in writing, software | |
| 11 # distributed under the License is distributed on an "AS-IS" BASIS, | |
| 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 13 # See the License for the specific language governing permissions and | |
| 14 # limitations under the License. | |
| 15 | |
| 16 """Medium tests for the gpylint auto-fixer.""" | |
| 17 | |
| 18 __author__ = 'robbyw@google.com (Robby Walker)' | |
| 19 | |
| 20 import StringIO | |
| 21 | |
| 22 import gflags as flags | |
| 23 import unittest as googletest | |
| 24 from closure_linter import error_fixer | |
| 25 from closure_linter import runner | |
| 26 | |
| 27 | |
| 28 _RESOURCE_PREFIX = 'closure_linter/testdata' | |
| 29 | |
| 30 flags.FLAGS.strict = True | |
| 31 flags.FLAGS.limited_doc_files = ('dummy.js', 'externs.js') | |
| 32 flags.FLAGS.closurized_namespaces = ('goog', 'dummy') | |
| 33 | |
| 34 | |
| 35 class FixJsStyleTest(googletest.TestCase): | |
| 36 """Test case to for gjslint auto-fixing.""" | |
| 37 | |
| 38 def setUp(self): | |
| 39 flags.FLAGS.dot_on_next_line = True | |
| 40 | |
| 41 def tearDown(self): | |
| 42 flags.FLAGS.dot_on_next_line = False | |
| 43 | |
| 44 def testFixJsStyle(self): | |
| 45 test_cases = [ | |
| 46 ['fixjsstyle.in.js', 'fixjsstyle.out.js'], | |
| 47 ['indentation.js', 'fixjsstyle.indentation.out.js'], | |
| 48 ['fixjsstyle.html.in.html', 'fixjsstyle.html.out.html'], | |
| 49 ['fixjsstyle.oplineend.in.js', 'fixjsstyle.oplineend.out.js']] | |
| 50 for [running_input_file, running_output_file] in test_cases: | |
| 51 print 'Checking %s vs %s' % (running_input_file, running_output_file) | |
| 52 input_filename = None | |
| 53 golden_filename = None | |
| 54 current_filename = None | |
| 55 try: | |
| 56 input_filename = '%s/%s' % (_RESOURCE_PREFIX, running_input_file) | |
| 57 current_filename = input_filename | |
| 58 | |
| 59 golden_filename = '%s/%s' % (_RESOURCE_PREFIX, running_output_file) | |
| 60 current_filename = golden_filename | |
| 61 except IOError as ex: | |
| 62 raise IOError('Could not find testdata resource for %s: %s' % | |
| 63 (current_filename, ex)) | |
| 64 | |
| 65 if running_input_file == 'fixjsstyle.in.js': | |
| 66 with open(input_filename) as f: | |
| 67 for line in f: | |
| 68 # Go to last line. | |
| 69 pass | |
| 70 self.assertTrue(line == line.rstrip(), '%s file should not end ' | |
| 71 'with a new line.' % (input_filename)) | |
| 72 | |
| 73 # Autofix the file, sending output to a fake file. | |
| 74 actual = StringIO.StringIO() | |
| 75 runner.Run(input_filename, error_fixer.ErrorFixer(actual)) | |
| 76 | |
| 77 # Now compare the files. | |
| 78 actual.seek(0) | |
| 79 expected = open(golden_filename, 'r') | |
| 80 | |
| 81 # Uncomment to generate new golden files and run | |
| 82 # open('/'.join(golden_filename.split('/')[4:]), 'w').write(actual.read()) | |
| 83 # actual.seek(0) | |
| 84 | |
| 85 self.assertEqual(actual.readlines(), expected.readlines()) | |
| 86 | |
| 87 def testAddProvideFirstLine(self): | |
| 88 """Tests handling of case where goog.provide is added.""" | |
| 89 original = [ | |
| 90 'dummy.bb.cc = 1;', | |
| 91 ] | |
| 92 | |
| 93 expected = [ | |
| 94 'goog.provide(\'dummy.bb\');', | |
| 95 '', | |
| 96 'dummy.bb.cc = 1;', | |
| 97 ] | |
| 98 | |
| 99 self._AssertFixes(original, expected, include_header=False) | |
| 100 | |
| 101 original = [ | |
| 102 '', | |
| 103 'dummy.bb.cc = 1;', | |
| 104 ] | |
| 105 | |
| 106 self._AssertFixes(original, expected, include_header=False) | |
| 107 | |
| 108 def testAddRequireFirstLine(self): | |
| 109 """Tests handling of case where goog.require is added.""" | |
| 110 original = [ | |
| 111 'a = dummy.bb.cc;', | |
| 112 ] | |
| 113 | |
| 114 expected = [ | |
| 115 'goog.require(\'dummy.bb\');', | |
| 116 '', | |
| 117 'a = dummy.bb.cc;', | |
| 118 ] | |
| 119 | |
| 120 self._AssertFixes(original, expected, include_header=False) | |
| 121 | |
| 122 original = [ | |
| 123 '', | |
| 124 'a = dummy.bb.cc;', | |
| 125 ] | |
| 126 | |
| 127 self._AssertFixes(original, expected, include_header=False) | |
| 128 | |
| 129 def testDeleteProvideAndAddProvideFirstLine(self): | |
| 130 """Tests handling of case where goog.provide is deleted and added. | |
| 131 | |
| 132 Bug 14832597. | |
| 133 """ | |
| 134 original = [ | |
| 135 'goog.provide(\'dummy.aa\');', | |
| 136 '', | |
| 137 'dummy.bb.cc = 1;', | |
| 138 ] | |
| 139 | |
| 140 expected = [ | |
| 141 'goog.provide(\'dummy.bb\');', | |
| 142 '', | |
| 143 'dummy.bb.cc = 1;', | |
| 144 ] | |
| 145 | |
| 146 self._AssertFixes(original, expected, include_header=False) | |
| 147 | |
| 148 original = [ | |
| 149 'goog.provide(\'dummy.aa\');', | |
| 150 'dummy.bb.cc = 1;', | |
| 151 ] | |
| 152 | |
| 153 self._AssertFixes(original, expected, include_header=False) | |
| 154 | |
| 155 def testDeleteProvideAndAddRequireFirstLine(self): | |
| 156 """Tests handling where goog.provide is deleted and goog.require added. | |
| 157 | |
| 158 Bug 14832597. | |
| 159 """ | |
| 160 original = [ | |
| 161 'goog.provide(\'dummy.aa\');', | |
| 162 '', | |
| 163 'a = dummy.bb.cc;', | |
| 164 ] | |
| 165 | |
| 166 expected = [ | |
| 167 'goog.require(\'dummy.bb\');', | |
| 168 '', | |
| 169 'a = dummy.bb.cc;', | |
| 170 ] | |
| 171 | |
| 172 self._AssertFixes(original, expected, include_header=False) | |
| 173 | |
| 174 original = [ | |
| 175 'goog.provide(\'dummy.aa\');', | |
| 176 'a = dummy.bb.cc;', | |
| 177 ] | |
| 178 | |
| 179 self._AssertFixes(original, expected, include_header=False) | |
| 180 | |
| 181 def testDeleteRequireAndAddRequireFirstLine(self): | |
| 182 """Tests handling of case where goog.require is deleted and added. | |
| 183 | |
| 184 Bug 14832597. | |
| 185 """ | |
| 186 original = [ | |
| 187 'goog.require(\'dummy.aa\');', | |
| 188 '', | |
| 189 'a = dummy.bb.cc;', | |
| 190 ] | |
| 191 | |
| 192 expected = [ | |
| 193 'goog.require(\'dummy.bb\');', | |
| 194 '', | |
| 195 'a = dummy.bb.cc;', | |
| 196 ] | |
| 197 | |
| 198 self._AssertFixes(original, expected, include_header=False) | |
| 199 | |
| 200 original = [ | |
| 201 'goog.require(\'dummy.aa\');', | |
| 202 'a = dummy.bb.cc;', | |
| 203 ] | |
| 204 | |
| 205 self._AssertFixes(original, expected, include_header=False) | |
| 206 | |
| 207 def testDeleteRequireAndAddProvideFirstLine(self): | |
| 208 """Tests handling where goog.require is deleted and goog.provide added. | |
| 209 | |
| 210 Bug 14832597. | |
| 211 """ | |
| 212 original = [ | |
| 213 'goog.require(\'dummy.aa\');', | |
| 214 '', | |
| 215 'dummy.bb.cc = 1;', | |
| 216 ] | |
| 217 | |
| 218 expected = [ | |
| 219 'goog.provide(\'dummy.bb\');', | |
| 220 '', | |
| 221 'dummy.bb.cc = 1;', | |
| 222 ] | |
| 223 | |
| 224 self._AssertFixes(original, expected, include_header=False) | |
| 225 | |
| 226 original = [ | |
| 227 'goog.require(\'dummy.aa\');', | |
| 228 'dummy.bb.cc = 1;', | |
| 229 ] | |
| 230 | |
| 231 self._AssertFixes(original, expected, include_header=False) | |
| 232 | |
| 233 def testMultipleProvideInsert(self): | |
| 234 original = [ | |
| 235 'goog.provide(\'dummy.bb\');', | |
| 236 'goog.provide(\'dummy.dd\');', | |
| 237 '', | |
| 238 'dummy.aa.ff = 1;', | |
| 239 'dummy.bb.ff = 1;', | |
| 240 'dummy.cc.ff = 1;', | |
| 241 'dummy.dd.ff = 1;', | |
| 242 'dummy.ee.ff = 1;', | |
| 243 ] | |
| 244 | |
| 245 expected = [ | |
| 246 'goog.provide(\'dummy.aa\');', | |
| 247 'goog.provide(\'dummy.bb\');', | |
| 248 'goog.provide(\'dummy.cc\');', | |
| 249 'goog.provide(\'dummy.dd\');', | |
| 250 'goog.provide(\'dummy.ee\');', | |
| 251 '', | |
| 252 'dummy.aa.ff = 1;', | |
| 253 'dummy.bb.ff = 1;', | |
| 254 'dummy.cc.ff = 1;', | |
| 255 'dummy.dd.ff = 1;', | |
| 256 'dummy.ee.ff = 1;', | |
| 257 ] | |
| 258 | |
| 259 self._AssertFixes(original, expected, include_header=False) | |
| 260 | |
| 261 def testMultipleRequireInsert(self): | |
| 262 original = [ | |
| 263 'goog.require(\'dummy.bb\');', | |
| 264 'goog.require(\'dummy.dd\');', | |
| 265 '', | |
| 266 'a = dummy.aa.ff;', | |
| 267 'b = dummy.bb.ff;', | |
| 268 'c = dummy.cc.ff;', | |
| 269 'd = dummy.dd.ff;', | |
| 270 'e = dummy.ee.ff;', | |
| 271 ] | |
| 272 | |
| 273 expected = [ | |
| 274 'goog.require(\'dummy.aa\');', | |
| 275 'goog.require(\'dummy.bb\');', | |
| 276 'goog.require(\'dummy.cc\');', | |
| 277 'goog.require(\'dummy.dd\');', | |
| 278 'goog.require(\'dummy.ee\');', | |
| 279 '', | |
| 280 'a = dummy.aa.ff;', | |
| 281 'b = dummy.bb.ff;', | |
| 282 'c = dummy.cc.ff;', | |
| 283 'd = dummy.dd.ff;', | |
| 284 'e = dummy.ee.ff;', | |
| 285 ] | |
| 286 | |
| 287 self._AssertFixes(original, expected, include_header=False) | |
| 288 | |
| 289 def testUnsortedRequires(self): | |
| 290 """Tests handling of unsorted goog.require statements without header. | |
| 291 | |
| 292 Bug 8398202. | |
| 293 """ | |
| 294 original = [ | |
| 295 'goog.require(\'dummy.aa\');', | |
| 296 'goog.require(\'dummy.Cc\');', | |
| 297 'goog.require(\'dummy.Dd\');', | |
| 298 '', | |
| 299 'function a() {', | |
| 300 ' dummy.aa.i = 1;', | |
| 301 ' dummy.Cc.i = 1;', | |
| 302 ' dummy.Dd.i = 1;', | |
| 303 '}', | |
| 304 ] | |
| 305 | |
| 306 expected = [ | |
| 307 'goog.require(\'dummy.Cc\');', | |
| 308 'goog.require(\'dummy.Dd\');', | |
| 309 'goog.require(\'dummy.aa\');', | |
| 310 '', | |
| 311 'function a() {', | |
| 312 ' dummy.aa.i = 1;', | |
| 313 ' dummy.Cc.i = 1;', | |
| 314 ' dummy.Dd.i = 1;', | |
| 315 '}', | |
| 316 ] | |
| 317 | |
| 318 self._AssertFixes(original, expected, include_header=False) | |
| 319 | |
| 320 def testMissingExtraAndUnsortedRequires(self): | |
| 321 """Tests handling of missing extra and unsorted goog.require statements.""" | |
| 322 original = [ | |
| 323 'goog.require(\'dummy.aa\');', | |
| 324 'goog.require(\'dummy.Cc\');', | |
| 325 'goog.require(\'dummy.Dd\');', | |
| 326 '', | |
| 327 'var x = new dummy.Bb();', | |
| 328 'dummy.Cc.someMethod();', | |
| 329 'dummy.aa.someMethod();', | |
| 330 ] | |
| 331 | |
| 332 expected = [ | |
| 333 'goog.require(\'dummy.Bb\');', | |
| 334 'goog.require(\'dummy.Cc\');', | |
| 335 'goog.require(\'dummy.aa\');', | |
| 336 '', | |
| 337 'var x = new dummy.Bb();', | |
| 338 'dummy.Cc.someMethod();', | |
| 339 'dummy.aa.someMethod();', | |
| 340 ] | |
| 341 | |
| 342 self._AssertFixes(original, expected) | |
| 343 | |
| 344 def testExtraRequireOnFirstLine(self): | |
| 345 """Tests handling of extra goog.require statement on the first line. | |
| 346 | |
| 347 There was a bug when fixjsstyle quits with an exception. It happened if | |
| 348 - the first line of the file is an extra goog.require() statement, | |
| 349 - goog.require() statements are not sorted. | |
| 350 """ | |
| 351 original = [ | |
| 352 'goog.require(\'dummy.aa\');', | |
| 353 'goog.require(\'dummy.cc\');', | |
| 354 'goog.require(\'dummy.bb\');', | |
| 355 '', | |
| 356 'var x = new dummy.bb();', | |
| 357 'var y = new dummy.cc();', | |
| 358 ] | |
| 359 | |
| 360 expected = [ | |
| 361 'goog.require(\'dummy.bb\');', | |
| 362 'goog.require(\'dummy.cc\');', | |
| 363 '', | |
| 364 'var x = new dummy.bb();', | |
| 365 'var y = new dummy.cc();', | |
| 366 ] | |
| 367 | |
| 368 self._AssertFixes(original, expected, include_header=False) | |
| 369 | |
| 370 def testUnsortedProvides(self): | |
| 371 """Tests handling of unsorted goog.provide statements without header. | |
| 372 | |
| 373 Bug 8398202. | |
| 374 """ | |
| 375 original = [ | |
| 376 'goog.provide(\'dummy.aa\');', | |
| 377 'goog.provide(\'dummy.Cc\');', | |
| 378 'goog.provide(\'dummy.Dd\');', | |
| 379 '', | |
| 380 'dummy.aa = function() {};' | |
| 381 'dummy.Cc = function() {};' | |
| 382 'dummy.Dd = function() {};' | |
| 383 ] | |
| 384 | |
| 385 expected = [ | |
| 386 'goog.provide(\'dummy.Cc\');', | |
| 387 'goog.provide(\'dummy.Dd\');', | |
| 388 'goog.provide(\'dummy.aa\');', | |
| 389 '', | |
| 390 'dummy.aa = function() {};' | |
| 391 'dummy.Cc = function() {};' | |
| 392 'dummy.Dd = function() {};' | |
| 393 ] | |
| 394 | |
| 395 self._AssertFixes(original, expected, include_header=False) | |
| 396 | |
| 397 def testMissingExtraAndUnsortedProvides(self): | |
| 398 """Tests handling of missing extra and unsorted goog.provide statements.""" | |
| 399 original = [ | |
| 400 'goog.provide(\'dummy.aa\');', | |
| 401 'goog.provide(\'dummy.Cc\');', | |
| 402 'goog.provide(\'dummy.Dd\');', | |
| 403 '', | |
| 404 'dummy.Cc = function() {};', | |
| 405 'dummy.Bb = function() {};', | |
| 406 'dummy.aa.someMethod = function();', | |
| 407 ] | |
| 408 | |
| 409 expected = [ | |
| 410 'goog.provide(\'dummy.Bb\');', | |
| 411 'goog.provide(\'dummy.Cc\');', | |
| 412 'goog.provide(\'dummy.aa\');', | |
| 413 '', | |
| 414 'dummy.Cc = function() {};', | |
| 415 'dummy.Bb = function() {};', | |
| 416 'dummy.aa.someMethod = function();', | |
| 417 ] | |
| 418 | |
| 419 self._AssertFixes(original, expected) | |
| 420 | |
| 421 def testNoRequires(self): | |
| 422 """Tests positioning of missing requires without existing requires.""" | |
| 423 original = [ | |
| 424 'goog.provide(\'dummy.Something\');', | |
| 425 '', | |
| 426 'dummy.Something = function() {};', | |
| 427 '', | |
| 428 'var x = new dummy.Bb();', | |
| 429 ] | |
| 430 | |
| 431 expected = [ | |
| 432 'goog.provide(\'dummy.Something\');', | |
| 433 '', | |
| 434 'goog.require(\'dummy.Bb\');', | |
| 435 '', | |
| 436 'dummy.Something = function() {};', | |
| 437 '', | |
| 438 'var x = new dummy.Bb();', | |
| 439 ] | |
| 440 | |
| 441 self._AssertFixes(original, expected) | |
| 442 | |
| 443 def testNoProvides(self): | |
| 444 """Tests positioning of missing provides without existing provides.""" | |
| 445 original = [ | |
| 446 'goog.require(\'dummy.Bb\');', | |
| 447 '', | |
| 448 'dummy.Something = function() {};', | |
| 449 '', | |
| 450 'var x = new dummy.Bb();', | |
| 451 ] | |
| 452 | |
| 453 expected = [ | |
| 454 'goog.provide(\'dummy.Something\');', | |
| 455 '', | |
| 456 'goog.require(\'dummy.Bb\');', | |
| 457 '', | |
| 458 'dummy.Something = function() {};', | |
| 459 '', | |
| 460 'var x = new dummy.Bb();', | |
| 461 ] | |
| 462 | |
| 463 self._AssertFixes(original, expected) | |
| 464 | |
| 465 def testOutputOkayWhenFirstTokenIsDeleted(self): | |
| 466 """Tests that autofix output is is correct when first token is deleted. | |
| 467 | |
| 468 Regression test for bug 4581567 | |
| 469 """ | |
| 470 original = ['"use strict";'] | |
| 471 expected = ["'use strict';"] | |
| 472 | |
| 473 self._AssertFixes(original, expected, include_header=False) | |
| 474 | |
| 475 def testGoogScopeIndentation(self): | |
| 476 """Tests Handling a typical end-of-scope indentation fix.""" | |
| 477 original = [ | |
| 478 'goog.scope(function() {', | |
| 479 ' // TODO(brain): Take over the world.', | |
| 480 '}); // goog.scope', | |
| 481 ] | |
| 482 | |
| 483 expected = [ | |
| 484 'goog.scope(function() {', | |
| 485 '// TODO(brain): Take over the world.', | |
| 486 '}); // goog.scope', | |
| 487 ] | |
| 488 | |
| 489 self._AssertFixes(original, expected) | |
| 490 | |
| 491 def testMissingEndOfScopeComment(self): | |
| 492 """Tests Handling a missing comment at end of goog.scope.""" | |
| 493 original = [ | |
| 494 'goog.scope(function() {', | |
| 495 '});', | |
| 496 ] | |
| 497 | |
| 498 expected = [ | |
| 499 'goog.scope(function() {', | |
| 500 '}); // goog.scope', | |
| 501 ] | |
| 502 | |
| 503 self._AssertFixes(original, expected) | |
| 504 | |
| 505 def testMissingEndOfScopeCommentWithOtherComment(self): | |
| 506 """Tests handling an irrelevant comment at end of goog.scope.""" | |
| 507 original = [ | |
| 508 'goog.scope(function() {', | |
| 509 "}); // I don't belong here!", | |
| 510 ] | |
| 511 | |
| 512 expected = [ | |
| 513 'goog.scope(function() {', | |
| 514 '}); // goog.scope', | |
| 515 ] | |
| 516 | |
| 517 self._AssertFixes(original, expected) | |
| 518 | |
| 519 def testMalformedEndOfScopeComment(self): | |
| 520 """Tests Handling a malformed comment at end of goog.scope.""" | |
| 521 original = [ | |
| 522 'goog.scope(function() {', | |
| 523 '}); // goog.scope FTW', | |
| 524 ] | |
| 525 | |
| 526 expected = [ | |
| 527 'goog.scope(function() {', | |
| 528 '}); // goog.scope', | |
| 529 ] | |
| 530 | |
| 531 self._AssertFixes(original, expected) | |
| 532 | |
| 533 def testEndsWithIdentifier(self): | |
| 534 """Tests Handling case where script ends with identifier. Bug 7643404.""" | |
| 535 original = [ | |
| 536 'goog.provide(\'xyz\');', | |
| 537 '', | |
| 538 'abc' | |
| 539 ] | |
| 540 | |
| 541 expected = [ | |
| 542 'goog.provide(\'xyz\');', | |
| 543 '', | |
| 544 'abc;' | |
| 545 ] | |
| 546 | |
| 547 self._AssertFixes(original, expected) | |
| 548 | |
| 549 def testFileStartsWithSemicolon(self): | |
| 550 """Tests handling files starting with semicolon. | |
| 551 | |
| 552 b/10062516 | |
| 553 """ | |
| 554 original = [ | |
| 555 ';goog.provide(\'xyz\');', | |
| 556 '', | |
| 557 'abc;' | |
| 558 ] | |
| 559 | |
| 560 expected = [ | |
| 561 'goog.provide(\'xyz\');', | |
| 562 '', | |
| 563 'abc;' | |
| 564 ] | |
| 565 | |
| 566 self._AssertFixes(original, expected, include_header=False) | |
| 567 | |
| 568 def testCodeStartsWithSemicolon(self): | |
| 569 """Tests handling code in starting with semicolon after comments. | |
| 570 | |
| 571 b/10062516 | |
| 572 """ | |
| 573 original = [ | |
| 574 ';goog.provide(\'xyz\');', | |
| 575 '', | |
| 576 'abc;' | |
| 577 ] | |
| 578 | |
| 579 expected = [ | |
| 580 'goog.provide(\'xyz\');', | |
| 581 '', | |
| 582 'abc;' | |
| 583 ] | |
| 584 | |
| 585 self._AssertFixes(original, expected) | |
| 586 | |
| 587 def _AssertFixes(self, original, expected, include_header=True): | |
| 588 """Asserts that the error fixer corrects original to expected.""" | |
| 589 if include_header: | |
| 590 original = self._GetHeader() + original | |
| 591 expected = self._GetHeader() + expected | |
| 592 | |
| 593 actual = StringIO.StringIO() | |
| 594 runner.Run('testing.js', error_fixer.ErrorFixer(actual), original) | |
| 595 actual.seek(0) | |
| 596 | |
| 597 expected = [x + '\n' for x in expected] | |
| 598 | |
| 599 self.assertListEqual(actual.readlines(), expected) | |
| 600 | |
| 601 def _GetHeader(self): | |
| 602 """Returns a fake header for a JavaScript file.""" | |
| 603 return [ | |
| 604 '// Copyright 2011 Google Inc. All Rights Reserved.', | |
| 605 '', | |
| 606 '/**', | |
| 607 ' * @fileoverview Fake file overview.', | |
| 608 ' * @author fake@google.com (Fake Person)', | |
| 609 ' */', | |
| 610 '' | |
| 611 ] | |
| 612 | |
| 613 | |
| 614 if __name__ == '__main__': | |
| 615 googletest.main() | |
| OLD | NEW |