| [ Index ] |
PHP Cross Reference of Limb3 |
[Summary view] [Print] [Text view]
1 <?php 2 /* 3 * Limb PHP Framework 4 * 5 * @link http://limb-project.com 6 * @copyright Copyright © 2004-2007 BIT(http://bit-creative.com) 7 * @license LGPL http://www.gnu.org/copyleft/lesser.html 8 */ 9 10 require_once('limb/wact/src/compiler/templatecompiler.inc.php'); 11 12 Mock::generate('WactParserListener', 'MockWactParserListener'); 13 14 class WactHTMLParserListenerStub implements WactHTMLParserListener 15 { 16 public $events = array(); 17 18 function characters($text, $location) 19 { 20 $this->events[] = array('characters', $text, $location); 21 } 22 23 function startTag($tag, $attributes, $location) 24 { 25 $this->events[] = array('startTag', $tag, $attributes, $location); 26 } 27 28 function endTag($tag, $location) 29 { 30 $this->events[] = array('endTag', $tag, $location); 31 } 32 33 function emptyTag($tag, $attributes, $location) 34 { 35 $this->events[] = array('emptyTag', $tag, $attributes, $location); 36 } 37 38 function instruction($type, $code, $location) 39 { 40 $this->events[] = array('instruction', $type, $code, $location); 41 } 42 } 43 44 class WactHTMLParserTest extends UnitTestCase 45 { 46 protected $parser; 47 protected $listener; 48 49 function setUp() 50 { 51 $this->listener = new WactHTMLParserListenerStub(); 52 $this->parser = new WactHTMLParser($this->listener); 53 $this->file_name = 'my_file'; 54 } 55 56 protected function _createLocation($line = 1) 57 { 58 return new WactSourceLocation('my_file', $line); 59 } 60 61 function testEmpty() 62 { 63 $this->parser->parse('', $this->file_name); 64 $this->assertEqual($this->listener->events, array()); 65 } 66 67 function testSimpleDataIsCharacters() 68 { 69 $location = $this->_createLocation(); 70 $this->parser->parse('stuff', $this->file_name); 71 72 $this->checkEventsCount(1); 73 $this->checkCharactersEvent(0, 'stuff', $location); 74 } 75 76 function testPreservingWhiteSpace() 77 { 78 $this->parser->parse(" stuff\t\r\n ", $this->file_name); 79 $this->checkEventsCount(1); 80 $this->checkCharactersEvent(0, " stuff\t\r\n "); 81 } 82 83 function testTagWithNoContentNoAttributes() 84 { 85 $location = $this->_createLocation(); 86 87 $this->parser->parse('<tag></tag>', $this->file_name); 88 89 $this->checkEventsCount(2); 90 $this->checkStartTagEvent(0, "tag", array(), $location); 91 $this->checkEndTagEvent(1, "tag", $location); 92 } 93 94 function testEmptyTag() 95 { 96 $location = $this->_createLocation(); 97 98 $this->parser->parse('<br/>', $this->file_name); 99 100 $this->checkEventsCount(1); 101 $this->checkEmptyTagEvent(0, "br", array(), $location); 102 } 103 104 function testTagWithContent() 105 { 106 $this->parser->parse('<tag>stuff</tag>', $this->file_name); 107 108 $this->checkEventsCount(3); 109 $this->checkStartTagEvent(0, "tag", array()); 110 $this->checkCharactersEvent(1, "stuff"); 111 $this->checkEndTagEvent(2, "tag"); 112 } 113 114 function testEmptyComment() 115 { 116 $this->parser->parse('<!---->', $this->file_name); 117 118 $this->checkEventsCount(1); 119 $this->checkCharactersEvent(0, "<!---->"); 120 } 121 122 function testTruncatedComment() 123 { 124 $location = $this->_createLocation(); 125 $this->parser->parse('stuff<!--', $this->file_name); 126 $this->checkEventsCount(2); 127 $this->checkCharactersEvent(0, 'stuff', $location); 128 $this->checkCharactersEvent(1, '<!--', $location); 129 } 130 131 function testTruncatedCommentNoClose() 132 { 133 $location = $this->_createLocation(); 134 $this->parser->parse('stuff<!-- blah', $this->file_name); 135 $this->checkEventsCount(2); 136 $this->checkCharactersEvent(0, 'stuff', $location); 137 $this->checkCharactersEvent(1, '<!-- blah', $location); 138 } 139 140 function testMalformedComment() 141 { 142 $location = $this->_createLocation(); 143 $this->parser->parse('<!--x->', $this->file_name); 144 $this->checkEventsCount(1); 145 $this->checkCharactersEvent(0, '<!--x->', $location); 146 } 147 148 function testAttributes() 149 { 150 $this->parser->parse('<tag a="A" b=\'B\' c = "C">', $this->file_name); 151 $this->checkEventsCount(1); 152 $this->checkStartTagEvent(0, "tag", array("a" => "A", "b" => "B", "c" => "C")); 153 } 154 155 function testEmptyAttributes() 156 { 157 $this->parser->parse('<tag a b c>', $this->file_name); 158 $this->checkEventsCount(1); 159 $this->checkStartTagEvent(0, "tag", array("a" => NULL, "b" => NULL, "c" => NULL)); 160 } 161 162 function testNastyAttributes() 163 { 164 $this->parser->parse("<tag a=\"&%$'?<>\" b='\r\n\t\"' c = ''>", $this->file_name); 165 $this->checkEventsCount(1); 166 $this->checkStartTagEvent(0, "tag", array("a" => "&%$'?<>", 167 "b" => "\r\n\t\"", 168 "c" => "")); 169 } 170 171 function testAttributesPadding() 172 { 173 $this->parser->parse("<tag\ta=\"A\"\rb='B'\nc = \"C\"\n>", $this->file_name); 174 $this->checkEventsCount(1); 175 $this->checkStartTagEvent(0, "tag", array("a" => "A", "b" => "B", "c" => "C")); 176 } 177 178 function testTagWithDoubleQuotedAttribute() 179 { 180 $this->parser->parse('<tag attribute="\'">', $this->file_name); 181 182 $this->checkEventsCount(1); 183 $this->checkStartTagEvent(0, "tag", array('attribute' => '\'')); 184 } 185 186 function testTagWithSingleQuotedAttribute() 187 { 188 $this->parser->parse('<tag attribute=\'"\'>', $this->file_name); 189 $this->checkEventsCount(1); 190 $this->checkStartTagEvent(0, "tag", array('attribute' => '"')); 191 } 192 193 function testTagNestedSingleQuoteAttributeThrowsException() 194 { 195 try 196 { 197 $this->parser->parse('<tag attribute=\'\'\'>', $this->file_name); 198 $this->assertTrue(false); 199 } 200 catch(WactException $e) 201 { 202 $this->assertWantedPattern('/Invalid tag attribute syntax/', $e->getMessage()); 203 $this->assertEqual($e->getParam('file'), $this->file_name); 204 $this->assertEqual($e->getParam('line'), 1); 205 } 206 } 207 208 function testTagNestedDoubleQuoteAttributeThrowsException() 209 { 210 try 211 { 212 $this->parser->parse('<tag attribute=""">', $this->file_name); 213 $this->assertTrue(false); 214 } 215 catch(WactException $e) 216 { 217 $this->assertWantedPattern('/Invalid tag attribute syntax/', $e->getMessage()); 218 $this->assertEqual($e->getParam('file'), $this->file_name); 219 $this->assertEqual($e->getParam('line'), 1); 220 } 221 } 222 223 function testTagNoSpaceAfterAttributeThrowsException() 224 { 225 try 226 { 227 $this->parser->parse('<tag attribute="test"extra>', $this->file_name); 228 $this->assertTrue(false); 229 } 230 catch(WactException $e) 231 { 232 $this->assertWantedPattern('/Invalid tag attribute syntax/', $e->getMessage()); 233 $this->assertEqual($e->getParam('file'), $this->file_name); 234 $this->assertEqual($e->getParam('line'), 1); 235 } 236 } 237 238 function testOpenTagMalformedCloseThrowsException() 239 { 240 try 241 { 242 $this->parser->parse('stuff<tag attribute=\'value\'/morestuff', $this->file_name); 243 $this->assertTrue(false); 244 } 245 catch(WactException $e) 246 { 247 $this->assertWantedPattern('/Invalid tag syntax/', $e->getMessage()); 248 $this->assertEqual($e->getParam('file'), $this->file_name); 249 $this->assertEqual($e->getParam('line'), 1); 250 } 251 } 252 253 function testOpenTagMalformedCloseThrowsException2() 254 { 255 try 256 { 257 $this->parser->parse('stuff<tag attribute=\'value\'/morestuff>', $this->file_name); 258 $this->assertTrue(false); 259 } 260 catch(WactException $e) 261 { 262 $this->assertWantedPattern('/Invalid tag syntax/', $e->getMessage()); 263 $this->assertEqual($e->getParam('file'), $this->file_name); 264 $this->assertEqual($e->getParam('line'), 1); 265 } 266 } 267 268 function testElementWithPreContent() 269 { 270 $this->parser->parse('stuff<br>', $this->file_name); 271 $this->checkEventsCount(2); 272 $this->checkCharactersEvent(0, "stuff"); 273 $this->checkStartTagEvent(1, "br", array()); 274 } 275 276 function testElementWithPostContent() 277 { 278 $this->parser->parse('<br>stuff', $this->file_name); 279 $this->checkEventsCount(2); 280 $this->checkStartTagEvent(0, "br", array()); 281 $this->checkCharactersEvent(1, "stuff"); 282 } 283 284 function testExpressionAfterTag() 285 { 286 $this->parser->parse('<br/>{$str|clip:5}', $this->file_name); 287 $this->checkEventsCount(2); 288 $this->checkEmptyTagEvent(0, "br", array()); 289 $this->checkCharactersEvent(1, '{$str|clip:5}'); 290 } 291 292 function testExpressionAfterTagWithArguments() 293 { 294 $this->parser->parse('<core:set str="abcdefgh" />{$str|clip:5}', $this->file_name); 295 $this->checkEventsCount(2); 296 $this->checkEmptyTagEvent(0, "core:set", array('str' => 'abcdefgh')); 297 $this->checkCharactersEvent(1, '{$str|clip:5}'); 298 } 299 300 function testMismatchedTags() 301 { 302 $this->parser->parse('<b><i>stuff</b></i>', $this->file_name); 303 $this->checkEventsCount(5); 304 $this->checkStartTagEvent(0, "b", array()); 305 $this->checkStartTagEvent(1, "i", array()); 306 $this->checkCharactersEvent(2, "stuff"); 307 $this->checkEndTagEvent(3, "b", array()); 308 $this->checkEndTagEvent(4, "i", array()); 309 } 310 311 function testScriptTagWithTagsInsideGeneratedCode() 312 { 313 $this->parser->parse('<script language="Javascript">document.write(\'<B>Test</B>\');</script>'); 314 $this->checkEventsCount(7); 315 $this->checkStartTagEvent(0, "script", array('language' => "Javascript")); 316 $this->checkCharactersEvent(1, 'document.write(\''); 317 $this->checkStartTagEvent(2, "B", array()); 318 $this->checkCharactersEvent(3, 'Test'); 319 $this->checkEndTagEvent(4, "B"); 320 $this->checkCharactersEvent(5, '\');'); 321 $this->checkEndTagEvent(6, "script"); 322 } 323 324 function testIgnoreTagsInsideCommentsBlock() 325 { 326 $this->parser->parse('<script language="Javascript"><!-- document.write(\'<B>Test</B>\'); --></script>'); 327 $this->checkEventsCount(3); 328 $this->checkStartTagEvent(0, "script", array('language' => "Javascript")); 329 $this->checkCharactersEvent(1, '<!-- document.write(\'<B>Test</B>\'); -->'); 330 $this->checkEndTagEvent(2, "script"); 331 } 332 333 function testTruncatedOpenTagChar() 334 { 335 $location = $this->_createLocation(); 336 $this->parser->parse('stuff<a', $this->file_name); 337 $this->checkEventsCount(2); 338 $this->checkCharactersEvent(0, 'stuff', $location); 339 $this->checkCharactersEvent(1, '<a', $location); 340 } 341 342 function testTruncatedOpenTag() 343 { 344 $location = $this->_createLocation(); 345 $this->parser->parse('stuff<tag', $this->file_name); 346 $this->checkCharactersEvent(0, 'stuff', $location); 347 $this->checkCharactersEvent(1, '<tag', $location); 348 } 349 350 function testTruncatedOpenTagWithSpace() 351 { 352 $location = $this->_createLocation(); 353 $this->parser->parse('stuff<tag ', $this->file_name); 354 $this->checkCharactersEvent(0, 'stuff', $location); 355 $this->checkCharactersEvent(1, '<tag ', $location); 356 } 357 358 function testTruncatedOpenTagMinimizedAttribute() 359 { 360 $location = $this->_createLocation(); 361 $this->parser->parse('stuff<tag attribute', $this->file_name); 362 $this->checkCharactersEvent(0, 'stuff', $location); 363 $this->checkCharactersEvent(1, '<tag attribute', $location); 364 } 365 366 function testTruncatedOpenTagMinimizedAttributeSpace() 367 { 368 $location = $this->_createLocation(); 369 $this->parser->parse('stuff<tag attribute ', $this->file_name); 370 $this->checkCharactersEvent(0, 'stuff', $location); 371 $this->checkCharactersEvent(1, '<tag attribute ', $location); 372 } 373 374 function testTruncatedOpenTagAttribute() 375 { 376 $location = $this->_createLocation(); 377 $this->parser->parse('stuff<tag attribute=', $this->file_name); 378 $this->checkCharactersEvent(0, 'stuff', $location); 379 $this->checkCharactersEvent(1, '<tag attribute=', $location); 380 } 381 382 function testTruncatedOpenTagAttributeAndSpace() 383 { 384 $location = $this->_createLocation(); 385 $this->parser->parse('stuff<tag attribute= ', $this->file_name); 386 $this->checkCharactersEvent(0, 'stuff', $location); 387 $this->checkCharactersEvent(1, '<tag attribute= ', $location); 388 } <