htmlprettyprinter_test.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.format.HtmlPrettyPrinterTest');
  15. goog.setTestOnly('goog.format.HtmlPrettyPrinterTest');
  16. goog.require('goog.format.HtmlPrettyPrinter');
  17. goog.require('goog.testing.MockClock');
  18. goog.require('goog.testing.jsunit');
  19. var COMPLEX_HTML = '<!DOCTYPE root-element [SYSTEM OR PUBLIC FPI] "uri" [' +
  20. '<!-- internal declarations -->]>' +
  21. '<html><head><title>My HTML</title><!-- my comment --></head>' +
  22. '<script> if(i<0)\nfoo; </script>' +
  23. '<body><h1>My Header</h1>My text.<br><b>My bold text.</b><hr>' +
  24. '<pre>My\npreformatted <br> HTML.</pre>5 < 10</body>' +
  25. '</html>';
  26. var mockClock;
  27. var mockClockTicks;
  28. function setUp() {
  29. mockClockTicks = 0;
  30. mockClock = new goog.testing.MockClock();
  31. mockClock.getCurrentTime = function() { return mockClockTicks++; };
  32. mockClock.install();
  33. }
  34. function tearDown() {
  35. if (mockClock) {
  36. mockClock.uninstall();
  37. }
  38. }
  39. function testSimpleHtml() {
  40. var actual = goog.format.HtmlPrettyPrinter.format('<br><b>bold</b>');
  41. assertEquals('<br>\n<b>bold</b>\n', actual);
  42. assertEquals(actual, goog.format.HtmlPrettyPrinter.format(actual));
  43. }
  44. function testSimpleHtmlMixedCase() {
  45. var actual = goog.format.HtmlPrettyPrinter.format('<BR><b>bold</b>');
  46. assertEquals('<BR>\n<b>bold</b>\n', actual);
  47. assertEquals(actual, goog.format.HtmlPrettyPrinter.format(actual));
  48. }
  49. function testComplexHtml() {
  50. var actual = goog.format.HtmlPrettyPrinter.format(COMPLEX_HTML);
  51. var expected = '<!DOCTYPE root-element [SYSTEM OR PUBLIC FPI] "uri" [' +
  52. '<!-- internal declarations -->]>\n' +
  53. '<html>\n' +
  54. '<head>\n' +
  55. '<title>My HTML</title>\n' +
  56. '<!-- my comment -->' +
  57. '</head>\n' +
  58. '<script> if(i<0)\nfoo; </script>\n' +
  59. '<body>\n' +
  60. '<h1>My Header</h1>\n' +
  61. 'My text.<br>\n' +
  62. '<b>My bold text.</b>\n' +
  63. '<hr>\n' +
  64. '<pre>My\npreformatted <br> HTML.</pre>\n' +
  65. '5 < 10' +
  66. '</body>\n' +
  67. '</html>\n';
  68. assertEquals(expected, actual);
  69. assertEquals(actual, goog.format.HtmlPrettyPrinter.format(actual));
  70. }
  71. function testTimeout() {
  72. var pp = new goog.format.HtmlPrettyPrinter(3);
  73. var actual = pp.format(COMPLEX_HTML);
  74. var expected = '<!DOCTYPE root-element [SYSTEM OR PUBLIC FPI] "uri" [' +
  75. '<!-- internal declarations -->]>\n' +
  76. '<html>\n' +
  77. '<head><title>My HTML</title><!-- my comment --></head>' +
  78. '<script> if(i<0)\nfoo; </script>' +
  79. '<body><h1>My Header</h1>My text.<br><b>My bold text.</b><hr>' +
  80. '<pre>My\npreformatted <br> HTML.</pre>5 < 10</body>' +
  81. '</html>\n';
  82. assertEquals(expected, actual);
  83. }
  84. function testKeepLeadingIndent() {
  85. var original = ' <b>Bold</b> <i>Ital</i> ';
  86. var expected = ' <b>Bold</b> <i>Ital</i>\n';
  87. assertEquals(expected, goog.format.HtmlPrettyPrinter.format(original));
  88. }
  89. function testTrimLeadingLineBreaks() {
  90. var original = '\n \t\r\n \n <b>Bold</b> <i>Ital</i> ';
  91. var expected = ' <b>Bold</b> <i>Ital</i>\n';
  92. assertEquals(expected, goog.format.HtmlPrettyPrinter.format(original));
  93. }
  94. function testExtraLines() {
  95. var original = '<br>\ntombrat';
  96. assertEquals(original + '\n', goog.format.HtmlPrettyPrinter.format(original));
  97. }
  98. function testCrlf() {
  99. var original = '<br>\r\none\r\ntwo<br>';
  100. assertEquals(original + '\n', goog.format.HtmlPrettyPrinter.format(original));
  101. }
  102. function testEndInLineBreak() {
  103. assertEquals('foo\n', goog.format.HtmlPrettyPrinter.format('foo'));
  104. assertEquals('foo\n', goog.format.HtmlPrettyPrinter.format('foo\n'));
  105. assertEquals('foo\n', goog.format.HtmlPrettyPrinter.format('foo\n\n'));
  106. assertEquals('foo<br>\n', goog.format.HtmlPrettyPrinter.format('foo<br>'));
  107. assertEquals('foo<br>\n', goog.format.HtmlPrettyPrinter.format('foo<br>\n'));
  108. }
  109. function testTable() {
  110. var original = '<table>' +
  111. '<tr><td>one.one</td><td>one.two</td></tr>' +
  112. '<tr><td>two.one</td><td>two.two</td></tr>' +
  113. '</table>';
  114. var expected = '<table>\n' +
  115. '<tr>\n<td>one.one</td>\n<td>one.two</td>\n</tr>\n' +
  116. '<tr>\n<td>two.one</td>\n<td>two.two</td>\n</tr>\n' +
  117. '</table>\n';
  118. assertEquals(expected, goog.format.HtmlPrettyPrinter.format(original));
  119. }
  120. /**
  121. * We have a sanity check in HtmlPrettyPrinter to make sure the regex index
  122. * advances after every match. We should never hit this, but we include it on
  123. * the chance there is some corner case where the pattern would match but not
  124. * process a new token. It's not generally a good idea to break the
  125. * implementation to test behavior, but this is the easiest way to mimic a
  126. * bad internal state.
  127. */
  128. function testRegexMakesProgress() {
  129. var original = goog.format.HtmlPrettyPrinter.TOKEN_REGEX_;
  130. try {
  131. // This regex matches \B, an index between 2 word characters, so the regex
  132. // index does not advance when matching this.
  133. goog.format.HtmlPrettyPrinter.TOKEN_REGEX_ =
  134. /(?:\B|<!--.*?-->|<!.*?>|<(\/?)(\w+)[^>]*>|[^<]+|<)/g;
  135. // It would work on this string.
  136. assertEquals('f o o\n', goog.format.HtmlPrettyPrinter.format('f o o'));
  137. // But not this one.
  138. var ex = assertThrows(
  139. 'should have failed for invalid regex - endless loop',
  140. goog.partial(goog.format.HtmlPrettyPrinter.format, COMPLEX_HTML));
  141. assertEquals(
  142. 'Regex failed to make progress through source html.', ex.message);
  143. } finally {
  144. goog.format.HtmlPrettyPrinter.TOKEN_REGEX_ = original;
  145. }
  146. }
  147. /**
  148. * FF3.0 doesn't like \n between <code></li></code> and <code></ul></code>.
  149. * See b/1520665.
  150. */
  151. function testLists() {
  152. var original = '<ul><li>one</li><ul><li>two</li></UL><li>three</li></ul>';
  153. var expected =
  154. '<ul><li>one</li>\n<ul><li>two</li></UL>\n<li>three</li></ul>\n';
  155. assertEquals(expected, goog.format.HtmlPrettyPrinter.format(original));
  156. }
  157. /**
  158. * We have a sanity check in HtmlPrettyPrinter to make sure the regex fully
  159. * tokenizes the string. We should never hit this, but we include it on the
  160. * chance there is some corner case where the pattern would miss a section of
  161. * original string. It's not generally a good idea to break the
  162. * implementation to test behavior, but this is the easiest way to mimic a
  163. * bad internal state.
  164. */
  165. function testAvoidDataLoss() {
  166. var original = goog.format.HtmlPrettyPrinter.TOKEN_REGEX_;
  167. try {
  168. // This regex does not match stranded '<' characters, so does not fully
  169. // tokenize the string.
  170. goog.format.HtmlPrettyPrinter.TOKEN_REGEX_ =
  171. /(?:<!--.*?-->|<!.*?>|<(\/?)(\w+)[^>]*>|[^<]+)/g;
  172. // It would work on this string.
  173. assertEquals('foo\n', goog.format.HtmlPrettyPrinter.format('foo'));
  174. // But not this one.
  175. var ex = assertThrows(
  176. 'should have failed for invalid regex - data loss',
  177. goog.partial(goog.format.HtmlPrettyPrinter.format, COMPLEX_HTML));
  178. assertEquals('Lost data pretty printing html.', ex.message);
  179. } finally {
  180. goog.format.HtmlPrettyPrinter.TOKEN_REGEX_ = original;
  181. }
  182. }