View Javadoc

1   package net.sourceforge.pmd.lang.jsp.ast;
2   
3   import static org.junit.Assert.assertEquals;
4   import static org.junit.Assert.assertFalse;
5   import static org.junit.Assert.assertTrue;
6   
7   import java.util.ArrayList;
8   import java.util.Collections;
9   import java.util.Comparator;
10  import java.util.Iterator;
11  import java.util.List;
12  import java.util.Set;
13  
14  import net.sourceforge.pmd.lang.ast.Node;
15  
16  import org.junit.Ignore;
17  import org.junit.Test;
18  /**
19   * Test parsing of a JSP in document style, by checking the generated AST.
20   *
21   * @author pieter_van_raemdonck - Application Engineers NV/SA - www.ae.be
22   *
23   */
24  public class JspDocStyleTest extends AbstractJspNodesTst {
25  
26  	/**
27  	 * Smoke test for JSP parser.
28  	 *
29  	 * @throws Throwable
30  	 */
31      @Test
32      public void testSimplestJsp() throws Throwable {
33  		assertNumberOfNodes(ASTElement.class, TEST_SIMPLEST_HTML, 1);
34  	}
35  
36  	/**
37  	 * Test the information on a Element and Attribute.
38  	 *
39  	 * @throws Throwable
40  	 */
41      @Test
42  	public void testElementAttributeAndNamespace() throws Throwable {
43  		Set<Object> nodes = getNodes(null, TEST_ELEMENT_AND_NAMESPACE);
44  
45  		Set<ASTElement> elementNodes = getNodesOfType(ASTElement.class, nodes);
46  		assertEquals("One element node expected!", 1, elementNodes.size());
47  		ASTElement element = elementNodes.iterator().next();
48  		assertEquals("Correct name expected!", "h:html", element.getName());
49  		assertEquals("Has namespace prefix!", true, element.isHasNamespacePrefix());
50  		assertEquals("Element is empty!", true, element.isEmpty());
51  		assertEquals("Correct namespace prefix of element expected!", "h", element
52  				.getNamespacePrefix());
53  		assertEquals("Correct local name of element expected!", "html", element
54  				.getLocalName());
55  
56  		Set<ASTAttribute> attributeNodes = getNodesOfType(ASTAttribute.class, nodes);
57  		assertEquals("One attribute node expected!", 1, attributeNodes.size());
58  		ASTAttribute attribute = (ASTAttribute) attributeNodes.iterator().next();
59  		assertEquals("Correct name expected!", "MyNsPrefix:MyAttr", attribute
60  				.getName());
61  		assertEquals("Has namespace prefix!", true, attribute.isHasNamespacePrefix());
62  		assertEquals("Correct namespace prefix of element expected!", "MyNsPrefix",
63  				attribute.getNamespacePrefix());
64  		assertEquals("Correct local name of element expected!", "MyAttr", attribute
65  				.getLocalName());
66  
67  	}
68  
69  	/**
70  	 * Test exposing a bug of parsing error when having a hash as last character
71  	 * in an attribute value.
72  	 *
73  	 */
74      @Test
75      public void testAttributeValueContainingHash()
76  	{
77  		Set<Object> nodes = getNodes(null, TEST_ATTRIBUTE_VALUE_CONTAINING_HASH);
78  
79  		Set<ASTAttribute> attributes = getNodesOfType(ASTAttribute.class, nodes);
80  		assertEquals("Three attributes expected!", 3, attributes.size());
81  
82  		List<ASTAttribute> attrsList = new ArrayList<ASTAttribute>(attributes);
83  		Collections.sort(attrsList, new Comparator<ASTAttribute>() {
84  			public int compare(ASTAttribute arg0, ASTAttribute arg1) {
85  				return arg0.getName().compareTo(arg1.getName());
86  			}
87  		});
88  
89  		ASTAttribute attr = attrsList.get(0);
90  		assertEquals("Correct attribute name expected!",
91  				"foo", attr.getName());
92  		assertEquals("Correct attribute value expected!",
93  				"CREATE", attr.getFirstDescendantOfType(ASTAttributeValue.class).getImage());
94  
95  		attr = attrsList.get(1);
96  		assertEquals("Correct attribute name expected!",
97  				"href", attr.getName());
98  		assertEquals("Correct attribute value expected!",
99  				"#", attr.getFirstDescendantOfType(ASTAttributeValue.class).getImage());
100 
101 		attr = attrsList.get(2);
102 		assertEquals("Correct attribute name expected!",
103 				"something", attr.getName());
104 		assertEquals("Correct attribute value expected!",
105 				"#yes#", attr.getFirstDescendantOfType(ASTAttributeValue.class).getImage());
106 	}
107 
108 	/**
109 	 * Test correct parsing of CDATA.
110 	 */
111     @Test
112     public void testCData() {
113 		Set<ASTCData> cdataNodes = getNodes(ASTCData.class, TEST_CDATA);
114 
115 		assertEquals("One CDATA node expected!", 1, cdataNodes.size());
116 		ASTCData cdata = (ASTCData) cdataNodes.iterator().next();
117 		assertEquals("Content incorrectly parsed!", " some <cdata> ]] ]> ", cdata
118 				.getImage());
119 	}
120 
121 	/**
122 	 * Test parsing of Doctype declaration.
123 	 */
124     @Test
125     public void testDoctype() {
126 		Set<Object> nodes = getNodes(null, TEST_DOCTYPE);
127 
128 		Set<ASTDoctypeDeclaration> docTypeDeclarations = getNodesOfType(ASTDoctypeDeclaration.class, nodes);
129 		assertEquals("One doctype declaration expected!", 1, docTypeDeclarations
130 				.size());
131 		ASTDoctypeDeclaration docTypeDecl = docTypeDeclarations
132 				.iterator().next();
133 		assertEquals("Correct doctype-name expected!", "html", docTypeDecl.getName());
134 
135 		Set<ASTDoctypeExternalId> externalIds = getNodesOfType(ASTDoctypeExternalId.class, nodes);
136 		assertEquals("One doctype external id expected!", 1, externalIds
137 				.size());
138 		ASTDoctypeExternalId externalId = (ASTDoctypeExternalId) externalIds
139 				.iterator().next();
140 		assertEquals("Correct external public id expected!", "-//W3C//DTD XHTML 1.1//EN",
141 				externalId.getPublicId());
142 		assertEquals("Correct external uri expected!", "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd",
143 				externalId.getUri());
144 
145 	}
146 
147 	/**
148 	 * Test parsing of a XML comment.
149 	 *
150 	 */
151     @Test
152     public void testComment() {
153 		Set<ASTCommentTag> comments = getNodes(ASTCommentTag.class, TEST_COMMENT);
154 		assertEquals("One comment expected!", 1, comments.size());
155 		ASTCommentTag comment = (ASTCommentTag) comments.iterator().next();
156 		assertEquals("Correct comment content expected!", "comment", comment.getImage());
157 	}
158 
159     /**
160      * Test parsing of HTML <script> element.
161      */
162     @Test
163     public void testHtmlScript() {
164 		Set<ASTHtmlScript> scripts = getNodes(ASTHtmlScript.class, TEST_HTML_SCRIPT);
165 		assertEquals("One script expected!", 1, scripts.size());
166 		ASTHtmlScript script = (ASTHtmlScript) scripts.iterator().next();
167 		assertEquals("Correct script content expected!", "Script!", script.getImage());
168     }
169     
170     /**
171      * Test parsing of HTML <script src="x"/> element. It might not be valid html
172      * but it is likely to appear in .JSP files.
173      */
174     @Test
175     public void testImportHtmlScript() {
176 		Set<ASTHtmlScript> scripts = getNodes(ASTHtmlScript.class, TEST_IMPORT_JAVASCRIPT);
177 		assertEquals("One script expected!", 1, scripts.size());
178 		ASTHtmlScript script = (ASTHtmlScript) scripts.iterator().next();
179 		List<ASTAttributeValue> value = script.findDescendantsOfType(ASTAttributeValue.class);
180 		assertEquals("filename.js",value.get(0).getImage());
181     }
182     
183     /**
184      * Test parsing of HTML <script> element.
185      */
186     @Test
187     public void testHtmlScriptWithAttribute() {
188 		Set<ASTHtmlScript> scripts = getNodes(ASTHtmlScript.class, TEST_HTML_SCRIPT_WITH_ATTRIBUTE);
189 		assertEquals("One script expected!", 1, scripts.size());
190 		ASTHtmlScript script = (ASTHtmlScript) scripts.iterator().next();
191 		assertEquals("Correct script content expected!", "Script!", script.getImage());
192 		List<ASTAttributeValue> attrs = script.findDescendantsOfType(ASTAttributeValue.class);
193 		assertTrue("text/javascript".equals(attrs.get(0).getImage()));
194     }
195     
196     /**
197      * A complex script containing HTML comments, escapes, quotes, etc.
198      */
199     @Test
200     public void testComplexHtmlScript(){
201     	Set<ASTHtmlScript> script = getNodes(ASTHtmlScript.class, TEST_COMPLEX_SCRIPT);
202     	assertEquals("One script expected!", 1, script.size());
203     	ASTHtmlScript next = script.iterator().next();
204 		assertTrue(next.getImage().contains("<!--"));
205     	Set<ASTCommentTag> comments = getNodes(ASTCommentTag.class, TEST_COMPLEX_SCRIPT);
206     	assertEquals("One comment expected!", 1, comments.size());
207     }
208     
209     /**
210      * Test parsing of HTML <script> element.
211      */
212     @Test
213     public void testInlineCss() {
214 		Set<ASTElement> scripts = getNodes(ASTElement.class, TEST_INLINE_STYLE);
215 		assertEquals("Three elements expected!", 3, scripts.size());
216     }
217     
218     /**
219      * Test parsing of HTML text within element.
220      */
221     @Test
222     public void testTextInTag() {
223 		Set<ASTText> scripts = getNodes(ASTText.class, TEST_TEXT_IN_TAG);
224 		assertEquals("One text chunk expected!", 1, scripts.size());
225 		ASTText script = (ASTText) scripts.iterator().next();
226 		assertEquals("Correct content expected!", " some text ", script.getImage());
227     }
228     
229     /**
230      * Test parsing of HTML with no spaces between tags. Parser is likely 
231      * in this scenario.
232      */
233     @Test
234     public void noSpacesBetweenTags() {
235 		Set<ASTElement> scripts = getNodes(ASTElement.class, TEST_TAGS_NO_SPACE);
236 		assertEquals("Two tags expected!", 2, scripts.size());
237 		List<ASTElement> elmts = sortNodesByName(scripts);
238 		Iterator<ASTElement> iterator = elmts.iterator();
239 		ASTElement script = (ASTElement) iterator.next();
240 		assertEquals("Correct content expected!", "a", script.getName());
241 		script = (ASTElement) iterator.next();
242 		assertEquals("Correct content expected!", "b", script.getName());
243     }
244     
245     /**
246      * the $ sign might trick the parser into thinking an EL is next.
247      * He should be able to treat it as plain text
248      */
249     @Test
250     public void unclosedTagsWithDollar(){
251     	Set<ASTText> scripts = getNodes(ASTText.class, TEST_TAGS_WITH_DOLLAR);
252 		assertEquals("Two text chunks expected!", 2, scripts.size());
253 		ASTText script = (ASTText) scripts.iterator().next();
254 		assertEquals("Correct content expected!", " $ ", script.getImage());
255     }
256     
257     /**
258      * Make sure EL expressions aren't treated as plain text when they
259      * are around unclosed tags.
260      */
261     @Test
262     public void unclosedTagsWithELWithin(){
263     	Set<ASTElExpression> scripts = getNodes(ASTElExpression.class, TEST_TAGS_WITH_EL_WITHIN);
264 		assertEquals("Two EL expressions expected!", 2, scripts.size());
265 		List<ASTElExpression> exprs = sortByImage(scripts);
266 		Iterator<ASTElExpression> iterator = exprs.iterator();
267 		ASTElExpression script = (ASTElExpression) iterator.next();
268 		assertEquals("Correct content expected!", "expr1", script.getImage());
269 		script = (ASTElExpression) iterator.next();
270 		assertEquals("Correct content expected!", "expr2", script.getImage());
271     }
272     
273     /**
274      * Make sure mixed expressions don't confuse the parser
275      */
276     @Test
277     public void mixedExpressions(){
278     	Set<ASTJspExpression> exprs = getNodes(ASTJspExpression.class, TEST_TAGS_WITH_MIXED_EXPRESSIONS);
279     	assertEquals("One JSP expression expected!", 1, exprs.size());
280     	assertEquals("Image of expression should be \"expr\"",
281     			"expr",exprs.iterator().next().getImage());
282     	Set<ASTElExpression> els = getNodes(ASTElExpression.class, TEST_TAGS_WITH_MIXED_EXPRESSIONS);
283 		assertEquals("Two EL expression expected!", 2, els.size());
284 		assertEquals("Image of el should be \"expr\"",
285 				"expr",els.iterator().next().getImage());
286 		
287 		Set<ASTUnparsedText> unparsedtexts = getNodes(ASTUnparsedText.class, TEST_TAGS_WITH_MIXED_EXPRESSIONS);
288 		List<ASTUnparsedText> sortedUnparsedTxts = sortByImage(unparsedtexts);
289 		assertEquals("Two unparsed texts expected!", 2, sortedUnparsedTxts.size());
290 		Iterator<ASTUnparsedText> iterator = sortedUnparsedTxts.iterator();
291 		assertEquals("Image of text should be \"\\${expr}\"",
292 				" \\${expr} ",iterator.next().getImage());
293 		assertEquals("Image of text should be \" aaa \"",
294 				" aaa ",iterator.next().getImage());
295 		
296 		// ASTText should contain the text between two tags.
297 		Set<ASTText> texts = getNodes(ASTText.class, TEST_TAGS_WITH_MIXED_EXPRESSIONS);
298 		List<ASTText> sortedTxts = sortByImage(texts);
299 		assertEquals("Two regular texts expected!", 2, sortedTxts.size());
300 		Iterator<ASTText> iterator2 = sortedTxts.iterator();
301 		assertEquals("Image of text should be \"\\${expr}\"",
302 				" \\${expr} ",iterator2.next().getImage());
303 		assertEquals("Image of text should be all text between two nodes" +
304 				" \"  aaa ${expr}#{expr} \"",
305 				" aaa ${expr}#{expr}",iterator2.next().getImage());
306     }
307     
308     
309     /**
310      * Make sure JSP expressions are properly detected when they are next 
311      * to unclosed tags.
312      */
313     @Test
314     public void unclosedTagsWithJspExpressionWithin(){
315     	Set<ASTJspExpression> scripts = getNodes(ASTJspExpression.class, TEST_TAGS_WITH_EXPRESSION_WITHIN);
316 		assertEquals("Two JSP expressions expected!", 2, scripts.size());
317 		ASTJspExpression script = (ASTJspExpression) scripts.iterator().next();
318 		assertEquals("Correct content expected!", "expr", script.getImage());
319     }
320     
321     
322     /**
323      * A dangling unopened ( just </closed> )  tag should not influence the parsing. 
324      */
325     @Test
326     @Ignore // sadly the number of 
327     // <opening> tags has to be >= then the number of </closing> tags
328     public void textBetweenUnopenedTag(){
329     	Set<ASTText> scripts = getNodes(ASTText.class, TEST_TEXT_WITH_UNOPENED_TAG);
330     	assertEquals("Two text chunks expected!", 2, scripts.size());
331 		ASTText script = (ASTText) scripts.iterator().next();
332 		assertEquals("Correct content expected!", "$", script.getImage());
333     }
334     
335     /**
336      * Parser should be able to handle documents which start or end with unparsed text 
337      */
338     @Test
339     @Ignore// sadly the number of 
340     // <opening> tags has to be >= then the number of </closing> tags
341     public void textMultipleClosingTags(){
342     	Set<ASTText> scripts = getNodes(ASTText.class, TEST_MULTIPLE_CLOSING_TAGS);
343     	assertEquals("Four text chunks expected!", 4, scripts.size());
344 		ASTText script = (ASTText) scripts.iterator().next();
345 		assertEquals("Correct content expected!", " some text ", script.getImage());
346     }
347     
348     
349     /**
350      * Test parsing of HTML <script> element.
351      */
352     @Test 
353     public void textAfterOpenAndClosedTag() {
354 		Set<ASTElement> nodes = getNodes(ASTElement.class, TEST_TEXT_AFTER_OPEN_AND_CLOSED_TAG);
355 		assertEquals("Two elements expected!", 2, nodes.size());
356 		List<ASTElement> elmts = sortNodesByName(nodes);
357 		assertEquals("First element should be a","a",elmts.get(0).getName());
358 		assertFalse("first element should be closed",elmts.get(0).isUnclosed());
359 		assertEquals("Second element should be b","b",elmts.get(1).getName());
360 		assertTrue("Second element should not be closed",elmts.get(1).isUnclosed());
361 		
362 		Set<ASTText> text = getNodes(ASTText.class, TEST_TEXT_AFTER_OPEN_AND_CLOSED_TAG);
363 		assertEquals("Two text chunks expected!", 2, text.size());
364     }
365     
366     @Test
367     public void  quoteEL(){
368     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_QUOTE_EL);
369 		assertEquals("One attribute expected!", 1, attributes.size());
370 		ASTAttributeValue attr =  attributes.iterator().next();
371 		assertEquals("Expected to detect proper value for attribute!", "${something}", attr.getImage());
372     }
373     
374     @Test
375     public void quoteExpression(){
376     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_QUOTE_EXPRESSION);
377 		assertEquals("One attribute expected!", 1, attributes.size());
378 		ASTAttributeValue attr =  attributes.iterator().next();
379 		assertEquals("Expected to detect proper value for attribute!", "<%=something%>", attr.getImage());
380     }
381     
382     
383     @Test
384     @Ignore // tags contain quotes and break attribute parsing 
385     public void quoteTagInAttribute(){
386     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_QUOTE_TAG_IN_ATTR);
387 		assertEquals("One attribute expected!", 1, attributes.size());
388 		ASTAttributeValue attr =  attributes.iterator().next();
389 		assertEquals("Expected to detect proper value for attribute!", 
390 				"<bean:write name=\"x\" property=\"z\">", attr.getImage());
391     }
392     /**
393      * smoke test for a non-quoted attribute value
394      */
395     @Test
396     public void noQuoteAttrValue() {
397     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_NO_QUOTE_ATTR);
398 		assertEquals("One attribute expected!", 1, attributes.size());
399 		ASTAttributeValue attr =  attributes.iterator().next();
400 		assertEquals("Expected to detect proper value for attribute!", "yes|", attr.getImage());
401     }
402     
403     
404     /**
405      * tests whether JSP el is properly detected as attribute value
406      */
407     @Test
408     public void noQuoteAttrWithJspEL(){
409     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_NO_QUOTE_ATTR_WITH_EL);
410 		assertEquals("two attributes expected!", 2, attributes.size());
411 		Iterator<ASTAttributeValue> iterator = attributes.iterator();
412 		ASTAttributeValue attr2 =  iterator.next();
413 		if ("url".equals(attr2.getImage())){
414 			// we have to employ this nasty work-around 
415 			// in order to ensure that we check the proper attribute
416 			attr2 = iterator.next();
417 		}
418 		assertEquals("Expected to detect proper value for EL in attribute!", "${something}", attr2.getImage());
419     }
420     
421     /**
422      * tests whether parse correctly detects presence of JSP expression <%= %>
423      * within an non-quoted attribute value
424      */
425     @Test
426     public void noQuoteAttrWithJspExpression(){
427     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_NO_QUOTE_ATTR_WITH_EXPRESSION);
428 		assertEquals("One attribute expected!", 1, attributes.size());
429 		ASTAttributeValue attr =  attributes.iterator().next();
430 		assertEquals("Expected to detect proper value for attribute!", "<%=something%>", attr.getImage());
431     }
432     
433     /**
434      * tests whether parse correctly interprets empty non quote attribute
435      */
436     @Test
437     public void noQuoteAttrEmpty(){
438     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_NO_QUOTE_EMPTY_ATTR);
439 		assertEquals("two attributes expected!", 2, attributes.size());
440 		Iterator<ASTAttributeValue> iterator = attributes.iterator();
441 		ASTAttributeValue attr =  iterator.next();
442 		if ("http://someHost:/some_URL".equals(attr.getImage())){
443 			// we have to employ this nasty work-around 
444 			// in order to ensure that we check the proper attribute
445 			attr = iterator.next();
446 		}
447 		assertEquals("Expected to detect proper value for attribute!", "", attr.getImage());
448     }
449     
450     /**
451      * tests whether parse correctly interprets an cr lf instead of an attribute
452      */
453     @Test
454     public void noQuoteAttrCrLf(){
455     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_NO_QUOTE_CR_LF_ATTR);
456 		assertEquals("One attribute expected!", 2, attributes.size());
457 		Iterator<ASTAttributeValue> iterator = attributes.iterator();
458 		ASTAttributeValue attr =  iterator.next();
459 		if ("http://someHost:/some_URL".equals(attr.getImage())){
460 			// we have to employ this nasty work-around 
461 			// in order to ensure that we check the proper attribute
462 			attr = iterator.next();
463 		}
464 		assertEquals("Expected to detect proper value for attribute!", "\r\n", attr.getImage());
465 		
466     }
467    
468     /**
469      * tests whether parse correctly interprets an tab instead of an attribute
470      */
471     @Test
472     public void noQuoteAttrTab(){
473     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_NO_QUOTE_TAB_ATTR);
474 		assertEquals("One attribute expected!", 1, attributes.size());
475 		Iterator<ASTAttributeValue> iterator = attributes.iterator();
476 		ASTAttributeValue attr =  iterator.next();
477 		assertEquals("Expected to detect proper value for attribute!", "\t", attr.getImage());
478 		
479     }
480     
481     /**
482      * tests whether parse does not fail in the presence of unclosed JSP expression <%= 
483      * within an non-quoted attribute value
484      */
485     @Test
486     public void noQuoteAttrWithMalformedJspExpression(){
487     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_NO_QUOTE_ATTR_WITH_MALFORMED_EXPR);
488 		assertEquals("One attribute expected!",1, attributes.size());
489 		ASTAttributeValue attr =  attributes.iterator().next();
490 		assertEquals("Expected to detect proper value for attribute!", "<%=something", attr.getImage());
491     }
492     
493     /**
494      * test a no quote attribute value which contains a scriptlet <% %> 
495      * within its value
496      */
497     @Test
498     @Ignore// nice test for future development
499     public void noQuoteAttrWithScriptletInValue(){
500     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_NO_QUOTE_ATTR_WITH_SCRIPTLET);
501 		assertEquals("One attribute expected!", 1, attributes.size());
502 		
503 		ASTAttributeValue attr =  attributes.iterator().next();
504 		assertEquals("Expected to detect proper value for attribute!", "<% String a = \"1\";%>", attr.getImage());
505     }
506     
507     /**
508      * test a no quote attribute value can contain a tag (e.g. attr=<bean:write property="value" />)
509      * 
510      */
511     @Test
512     @Ignore// nice test for future development
513     public void noQuoteAttrWithBeanWriteTagAsValue(){
514     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_NO_QUOTE_TAG_IN_ATTR);
515 		assertEquals("One attribute expected!", 1, attributes.size());
516 		
517 		ASTAttributeValue attr =  attributes.iterator().next();
518 		assertEquals("Expected to detect proper value for attribute!", "<% String a = \"1\";%>", attr.getImage());
519     }
520     
521     /**
522      * test a quote attribute value can contain a tag (e.g. attr="<bean:write property="value" />" )
523      * Not sure if it's legal JSP code but most JSP engine accept and properly treat 
524      * this value at runtime
525      */
526     @Test
527     @Ignore// nice test for future development
528     public void quoteAttrWithBeanWriteTagAsValue(){
529     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_NO_QUOTE_TAG_IN_ATTR);
530 		assertEquals("One attribute expected!", 1, attributes.size());
531 		
532 		ASTAttributeValue attr =  attributes.iterator().next();
533 		assertEquals("Expected to detect proper value for attribute!", "<% String a = \"1\";%>", attr.getImage());
534     }
535     
536     /**
537      * test a no quote attribute value which contains the EL dollar sign $
538      * within its value
539      */
540     @Test
541     @Ignore// nice test for future development
542     public void noQuoteAttrWithDollarSignInValue(){
543     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, 
544     			TEST_NO_QUOTE_ATTR_WITH_DOLLAR);
545 		assertEquals("One attribute expected!", 2, attributes.size());
546 		ASTAttributeValue attr =  attributes.iterator().next();
547 		assertEquals("Expected to detect proper value for attribute!", "${something", attr.getImage());
548     }
549     
550     /**
551      * test a no quote attribute value which contains the EL sharp sign #
552      * within its value
553      */
554     @Test
555     @Ignore// nice test for future development
556     public void noQuoteAttrWithSharpSymbolInValue(){
557     	Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class,
558     			TEST_NO_QUOTE_ATTR_WITH_HASH);
559 		assertEquals("One attribute expected!", 1, attributes.size());
560 		ASTAttributeValue attr =  attributes.iterator().next();
561 		assertEquals("Expected to detect proper value for attribute!", "#{something", attr.getImage());
562     }
563     
564     @Test
565     public void unclosedTag(){
566     	Set<ASTElement> elements = getNodes(ASTElement.class, TEST_UNCLOSED_SIMPLE);
567     	List<ASTElement> sortedElmnts = sortNodesByName(elements);
568 		assertEquals("2 tags expected",2,elements.size());
569 		assertEquals("First element should be sorted tag:if",
570 				"tag:if",sortedElmnts.get(0).getName());
571 		assertEquals("Second element should be tag:someTag",
572 				"tag:someTag",sortedElmnts.get(1).getName());
573 		
574 		assertTrue(sortedElmnts.get(0).isEmpty());
575 		assertTrue(sortedElmnts.get(0).isUnclosed());
576 		assertFalse(sortedElmnts.get(1).isEmpty());
577 		assertFalse(sortedElmnts.get(1).isUnclosed());
578     }
579     
580     @Test
581     public void unclosedTagAndNoQuotesForAttribute(){
582     	Set<ASTElement> elements = getNodes(ASTElement.class, TEST_UNCLOSED_NO_QUOTE_ATTR);
583     	List<ASTElement> sortedElmnts = sortNodesByName(elements);
584 		assertEquals("2 tags expected",2,elements.size());
585 		assertEquals("First element should be sorted tag:if",
586 				"tag:if",sortedElmnts.get(0).getName());
587 		assertEquals("Second element should be tag:someTag",
588 				"tag:someTag",sortedElmnts.get(1).getName());
589 		
590 		assertTrue(sortedElmnts.get(0).isEmpty());
591 		assertTrue(sortedElmnts.get(0).isUnclosed());
592 		assertFalse(sortedElmnts.get(1).isEmpty());
593 		assertFalse(sortedElmnts.get(1).isUnclosed());
594     }
595     
596     @Test
597     public void unclosedTagMultipleLevels(){
598     	Set<ASTElement> elements = getNodes(ASTElement.class, TEST_UNCLOSED_MULTIPLE_LEVELS);
599     	List<ASTElement> sortedElmnts = sortNodesByName(elements);
600 		assertEquals("3 tags expected",3,elements.size());
601 		assertEquals("First element should be sorted tag:someTag",
602 				"tag:someTag",sortedElmnts.get(0).getName());
603 		assertEquals("Second element should be tag:someTag",
604 				"tag:someTag",sortedElmnts.get(1).getName());
605 		assertEquals("Third element should be tag:x",
606 				"tag:x",sortedElmnts.get(2).getName());
607 		
608 		assertFalse(sortedElmnts.get(0).isEmpty());
609 		assertFalse(sortedElmnts.get(0).isUnclosed());
610 		
611 		assertTrue(sortedElmnts.get(1).isEmpty());
612 		assertTrue(sortedElmnts.get(1).isUnclosed());
613 		
614 		assertFalse(sortedElmnts.get(2).isEmpty());
615 		assertFalse(sortedElmnts.get(2).isUnclosed());
616     }
617     
618     /**
619      * <html> <a1> <a2/> <b/> </a1> </html>
620      */
621     @Test
622     public void nestedEmptyTags(){
623     	Set<ASTElement> elements = getNodes(ASTElement.class, TEST_MULTIPLE_EMPTY_TAGS);
624     	List<ASTElement> sortedElmnts = sortNodesByName(elements);
625 		assertEquals("4 tags expected",4,elements.size());
626 		assertEquals("First element should a1",
627 				"a1",sortedElmnts.get(0).getName());
628 		assertEquals("Second element should be a2",
629 				"a2",sortedElmnts.get(1).getName());
630 		assertEquals("Third element should be b",
631 				"b",sortedElmnts.get(2).getName());
632 		assertEquals("Third element should be html",
633 				"html",sortedElmnts.get(3).getName());
634 		
635 		
636 		//  a1 
637 		assertFalse(sortedElmnts.get(0).isEmpty());
638 		assertFalse(sortedElmnts.get(0).isUnclosed());
639 		
640 		//  a2
641 		assertTrue(sortedElmnts.get(1).isEmpty());
642 		assertFalse(sortedElmnts.get(1).isUnclosed());
643 		
644 		// b
645 		assertTrue(sortedElmnts.get(2).isEmpty());
646 		assertFalse(sortedElmnts.get(2).isUnclosed());
647 		
648 		//html
649 		assertFalse(sortedElmnts.get(3).isEmpty());
650 		assertFalse(sortedElmnts.get(3).isUnclosed());
651 		
652     }
653     
654     /**
655      * <html> <a1> <a2> <a3> </a2> </a1> <b/> <a4/> </html>
656      */
657     @Test
658     public void nestedMultipleTags(){
659     	Set<ASTElement> elements = getNodes(ASTElement.class, TEST_MULTIPLE_NESTED_TAGS);
660     	List<ASTElement> sortedElmnts = sortNodesByName(elements);
661 		assertEquals("4 tags expected",6,elements.size());
662 		assertEquals("First element should a1",
663 				"a1",sortedElmnts.get(0).getName());
664 		assertEquals("Second element should be a2",
665 				"a2",sortedElmnts.get(1).getName());
666 		assertEquals("Third element should be a3",
667 				"a3",sortedElmnts.get(2).getName());
668 		assertEquals("Forth element should be a4",
669 				"a4",sortedElmnts.get(3).getName());
670 		assertEquals("Fifth element should be b",
671 				"b",sortedElmnts.get(4).getName());
672 		assertEquals("Sixth element should be html",
673 				"html",sortedElmnts.get(5).getName());
674 		
675 		
676 		//  a1 not empty and closed
677 		assertFalse(sortedElmnts.get(0).isEmpty());
678 		assertFalse(sortedElmnts.get(0).isUnclosed());
679 		
680 		//  a2  not empty and closed
681 		assertFalse(sortedElmnts.get(1).isEmpty());
682 		assertFalse(sortedElmnts.get(1).isUnclosed());
683 		
684 		//  a3 empty and not closed
685 		assertTrue(sortedElmnts.get(2).isEmpty());
686 		assertTrue(sortedElmnts.get(2).isUnclosed());
687 		
688 		//  a4 empty but closed
689 		assertTrue(sortedElmnts.get(3).isEmpty());
690 		assertFalse(sortedElmnts.get(3).isUnclosed());
691 		
692 		//  b empty but closed
693 		assertTrue(sortedElmnts.get(4).isEmpty());
694 		assertFalse(sortedElmnts.get(4).isUnclosed());
695 			
696 		//html not empty and closed
697 		assertFalse(sortedElmnts.get(5).isEmpty());
698 		assertFalse(sortedElmnts.get(5).isUnclosed());
699 		
700     }
701     
702     /**
703      * will test <x> <a> <b> <b> </x> </a> </x> . 
704      * Here x is the first tag to be closed thus rendering the next close of a (</a>)
705      * to be disregarded. 
706      */
707     @Test
708     public void unclosedParentTagClosedBeforeChild(){
709     	Set<ASTElement> elements = getNodes(ASTElement.class, 
710     			TEST_UNCLOSED_END_AFTER_PARENT_CLOSE);
711     	List<ASTElement> sortedElmnts = sortNodesByName(elements);
712 		assertEquals("4 tags expected",4,elements.size());
713 		assertEquals("First element should be 'a'",
714 				"a",sortedElmnts.get(0).getName());
715 		assertEquals("Second element should be b",
716 				"b",sortedElmnts.get(1).getName());
717 		assertEquals("Third element should be b",
718 				"b",sortedElmnts.get(2).getName());
719 		assertEquals("Forth element should be x",
720 				"x",sortedElmnts.get(3).getName());
721 		
722 		//a
723 		assertTrue(sortedElmnts.get(0).isEmpty());
724 		assertTrue(sortedElmnts.get(0).isUnclosed());
725 		
726 		//b
727 		assertTrue(sortedElmnts.get(1).isEmpty());
728 		assertTrue(sortedElmnts.get(1).isUnclosed());
729 		
730 		//b
731 		assertTrue(sortedElmnts.get(2).isEmpty());
732 		assertTrue(sortedElmnts.get(2).isUnclosed());
733 		
734 		//x
735 		assertFalse(sortedElmnts.get(3).isEmpty());
736 		assertFalse(sortedElmnts.get(3).isUnclosed());
737     }
738     
739     
740     /**
741      * <x> <a> <b> <b> </z> </a> </x>
742      * An unmatched closing of 'z' appears randomly in the document. This
743      * should be disregarded and structure of children and parents should not be influenced.
744      * in other words </a> should close the first <a> tag , </x> should close the first
745      *  <x>, etc.
746      */
747     @Test
748     public void unmatchedTagDoesNotInfluenceStructure(){
749     	Set<ASTElement> elements = getNodes(ASTElement.class, 
750     			TEST_UNCLOSED_UNMATCHED_CLOSING_TAG);
751     	List<ASTElement> sortedElmnts = sortNodesByName(elements);
752 		assertEquals("4 tags expected",4,elements.size());
753 		assertEquals("First element should be 'a'",
754 				"a",sortedElmnts.get(0).getName());
755 		assertEquals("Second element should be b",
756 				"b",sortedElmnts.get(1).getName());
757 		assertEquals("Third element should be b",
758 				"b",sortedElmnts.get(2).getName());
759 		assertEquals("Forth element should be x",
760 				"x",sortedElmnts.get(3).getName());
761 		
762 		//a is not empty and closed
763 		assertFalse(sortedElmnts.get(0).isEmpty());
764 		assertFalse(sortedElmnts.get(0).isUnclosed());
765 		
766 		//b empty and unclosed
767 		assertTrue(sortedElmnts.get(1).isEmpty());
768 		assertTrue(sortedElmnts.get(1).isUnclosed());
769 		
770 		//b empty and unclosed
771 		assertTrue(sortedElmnts.get(2).isEmpty());
772 		assertTrue(sortedElmnts.get(2).isUnclosed());
773 		
774 		//x not empty and closed
775 		assertFalse(sortedElmnts.get(3).isEmpty());
776 		assertFalse(sortedElmnts.get(3).isUnclosed());
777     }
778     
779     /**
780      * <a> <x> <a> <b> <b> </z> </a> </x>
781      * An unmatched closing of 'z' appears randomly in the document. This
782      * should be disregarded and structure of children and parents should not be influenced.
783      * Also un unclosed <a> tag appears at the start of the document
784      */
785     @Test
786     public void unclosedStartTagWithUnmatchedCloseOfDifferentTag(){
787     	Set<ASTElement> elements = getNodes(ASTElement.class, 
788     			TEST_UNCLOSED_START_TAG_WITH_UNMATCHED_CLOSE);
789     	List<ASTElement> sortedElmnts = sortNodesByName(elements);
790 		assertEquals("5 tags expected",5,elements.size());
791 		assertEquals("First element should be 'a'",
792 				"a",sortedElmnts.get(0).getName());
793 		assertEquals("Second element should be a",
794 				"a",sortedElmnts.get(1).getName());
795 		assertEquals("Third element should be b",
796 				"b",sortedElmnts.get(2).getName());
797 		assertEquals("Forth element should be b",
798 				"b",sortedElmnts.get(3).getName());
799 		assertEquals("Fifth element should be x",
800 				"x",sortedElmnts.get(4).getName());
801 		
802 		//first a is empty and unclosed
803 		assertTrue(sortedElmnts.get(0).isEmpty());
804 		assertTrue(sortedElmnts.get(0).isUnclosed());
805 		
806 		//second a not empty and closed
807 		assertFalse(sortedElmnts.get(1).isEmpty());
808 		assertFalse(sortedElmnts.get(1).isUnclosed());
809 		
810 		//b empty and unclosed
811 		assertTrue(sortedElmnts.get(2).isEmpty());
812 		assertTrue(sortedElmnts.get(2).isUnclosed());
813 		
814 		//b empty and unclosed
815 		assertTrue(sortedElmnts.get(3).isEmpty());
816 		assertTrue(sortedElmnts.get(3).isUnclosed());
817 				
818 		//x not empty and closed
819 		assertFalse(sortedElmnts.get(4).isEmpty());
820 		assertFalse(sortedElmnts.get(4).isUnclosed());
821     }
822     
823     /**
824      * {@link #TEST_UNCLOSED_END_OF_DOC}
825      * <tag:x> <tag:y> 
826      * Tests whether parser breaks on no closed tags at all
827      */
828     //This is yet to be improved. If a closing tag does not 
829     // exist no tags will be marked as empty :(
830     @Ignore
831     @Test
832     public void unclosedEndOfDoc(){
833     	Set<ASTElement> elements = getNodes(ASTElement.class, 
834     			TEST_UNCLOSED_END_OF_DOC);
835     	List<ASTElement> sortedElmnts = sortNodesByName(elements);
836 		assertEquals("2 tags expected",2,elements.size());
837 		assertEquals("First element should be 'tag:x'",
838 				"tag:x",sortedElmnts.get(0).getName());
839 		assertEquals("Second element should be tag:y",
840 				"tag:y",sortedElmnts.get(1).getName());
841 		
842 		//b
843 		//assertTrue(sortedElmnts.get(0).isEmpty());
844 		assertTrue(sortedElmnts.get(0).isUnclosed());
845 				
846 		//b
847 		assertTrue(sortedElmnts.get(1).isEmpty());
848 		assertTrue(sortedElmnts.get(1).isUnclosed());
849     }
850     
851     /**
852      * will sort the AST element in list in alphabetical order and if tag name 
853      * is the same it will sort against o1.getBeginColumn() +""+ o1.getBeginLine().
854      * so first criteria is the name, then the second is the column +""+line string.
855      * @param elements
856      * @return
857      */
858     private List<ASTElement> sortNodesByName(Set<ASTElement> elements){
859     	List<ASTElement> list = new ArrayList<ASTElement>();
860     	list.addAll(elements);
861     	Collections.sort(list, new Comparator<ASTElement>() {
862     		public int compare(ASTElement o1, ASTElement o2) {
863     			if (o1.getName() == null)
864     				return Integer.MIN_VALUE;
865     			if (o2.getName() == null)
866     				return Integer.MAX_VALUE;
867     			if (o1.getName().equals(o2.getName())){
868     				String o1Value = o1.getBeginColumn() +""+ o1.getBeginLine();
869     				String o2Value = o2.getBeginColumn() +""+ o2.getBeginLine();
870     				return o1Value.compareTo(o2Value);
871     			}
872     			return o1.getName().compareTo(o2.getName());
873     		}
874 		});
875     	return list;
876     }
877     
878     /**
879      * will sort the AST node by the image name.
880      * @param elements
881      * @return
882      */
883     private <T extends Node> List<T> sortByImage(Set<T> elements){
884     	List<T> list = new ArrayList<T>();
885     	list.addAll(elements);
886     	Collections.sort(list, new Comparator<Node>() {
887     		public int compare(Node o1, Node o2) {
888     			if (o1.getImage() == null)
889     				return Integer.MIN_VALUE;
890     			if (o2.getImage() == null)
891     				return Integer.MAX_VALUE;
892     			if (o1.getImage().equals(o2.getImage())){
893     				String o1Value = o1.getBeginColumn() +""+ o1.getBeginLine();
894     				String o2Value = o2.getBeginColumn() +""+ o2.getBeginLine();
895     				return o1Value.compareTo(o2Value);
896     			}
897     			return o1.getImage().compareTo(o2.getImage());
898     		}
899 		});
900     	return list;
901     }
902     
903 
904 	private static final String TEST_SIMPLEST_HTML = "<html/>";
905 
906 	private static final String TEST_ELEMENT_AND_NAMESPACE = "<h:html MyNsPrefix:MyAttr='MyValue'/>";
907 
908 	private static final String TEST_CDATA = "<html><![CDATA[ some <cdata> ]] ]> ]]></html>";
909 
910 	private static final String TEST_DOCTYPE = "<?xml version=\"1.0\" standalone='yes'?>\n"
911 			+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
912 			+ "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
913 			+ "<greeting>Hello, world!</greeting>";
914 
915 	private static final String TEST_COMMENT = "<html><!-- comment --></html>";
916 
917 	private static final String TEST_ATTRIBUTE_VALUE_CONTAINING_HASH =
918 		"<tag:if something=\"#yes#\" foo=\"CREATE\">  <a href=\"#\">foo</a> </tag:if>";
919 
920 	private static final String TEST_HTML_SCRIPT =
921 			"<html><head><script>Script!</script></head></html>";
922 
923 	private static final String TEST_IMPORT_JAVASCRIPT =
924 			"<html><head><script src=\"filename.js\" type=\"text/javascript\"/></head></html>";
925 
926 	private static final String TEST_HTML_SCRIPT_WITH_ATTRIBUTE =
927 			"<html><head><script type=\"text/javascript\">Script!</script></head></html>";
928 	
929 	private static final String TEST_COMPLEX_SCRIPT = 
930 			"<HTML><BODY><!--Java Script-->" +
931 			"<SCRIPT language='JavaScript' type='text/javascript'>" +
932 			"<!--function calcDays(){" +
933 			" date1 = date1.split(\"-\");  date2 = date2.split(\"-\");" +
934 			" var sDate = new Date(date1[0]+\"/\"+date1[1]+\"/\"+date1[2]);" +
935 			" var eDate = new Date(date2[0]+\"/\"+date2[1]+\"/\"+date2[2]);" +
936 			" onload=calcDays;//-->" +
937 			"</SCRIPT></BODY></HTML>;";
938 	
939 	private static final String TEST_INLINE_STYLE =
940 			"<html><head><style> div { color:red; } </style></head></html>";
941 	
942 	private static final String TEST_TEXT_IN_TAG=
943 			"<a> some text </a>";
944 	
945 	private static final String TEST_TAGS_NO_SPACE =
946 			"<a><b></a>";
947 	
948 	private static final String TEST_TAGS_WITH_DOLLAR =
949 			"<a> $ <b> $ </a>";
950 	
951 	private static final String TEST_TAGS_WITH_EL_WITHIN =
952 			"<a>#{expr1}<b>${expr2}</a>";
953 	
954 	private static final String TEST_TAGS_WITH_MIXED_EXPRESSIONS =
955 			"<a> aaa ${expr} #{expr} <%=expr%> <b> \\${expr} </a>";
956 	
957 	private static final String TEST_TAGS_WITH_EXPRESSION_WITHIN =
958 			"<a> <%=expr%> <b> <%=expr%> </a>";
959 	
960 	private static final String TEST_TEXT_AFTER_OPEN_AND_CLOSED_TAG =
961 			"<a> some text <b> some text </a>";
962 	
963 	private static final String TEST_TEXT_WITH_UNOPENED_TAG =
964 			"<a> some text </b> some text </a>";
965 	
966 	private static final String TEST_MULTIPLE_CLOSING_TAGS =
967 			"<a> some text </b> </b> </b> some text </a>";
968 	
969 	private static final String TEST_QUOTE_EL = 
970 			"<tag:if something=\"${something}\" > </tag:if>";
971 	
972 	private static final String TEST_QUOTE_EXPRESSION = 
973 			"<tag:if something=\"<%=something%>\" >  </tag:if>";
974 	
975 	private static final String TEST_QUOTE_TAG_IN_ATTR =
976 			"<tag:if something=\"<bean:write name=\"x\" property=\"z\">\" >  " +
977 			"<a href=http://someHost:/some_URL >foo</a> </tag:if>";
978 	
979 	private static final String TEST_NO_QUOTE_ATTR = 
980 "<tag:if something=yes| > </tag:if>";
981 	
982 	private static final String TEST_NO_QUOTE_EMPTY_ATTR = 
983 			"<tag:if something= >  <a href=http://someHost:/some_URL >foo</a> </tag:if>";
984 	
985 	private static final String TEST_NO_QUOTE_TAG_IN_ATTR =
986 			"<tag:if something=<bean:write name=\"x\" property=\"z\"> >  <a href=http://someHost:/some_URL >foo</a> </tag:if>";
987 	
988 	private static final String TEST_NO_QUOTE_CR_LF_ATTR = 
989 			"<tag:if something=\r\n >  <a href=http://someHost:/some_URL >foo</a> </tag:if>";
990 	
991 	private static final String TEST_NO_QUOTE_TAB_ATTR = 
992 			"<tag:if something=\t >   </tag:if>";
993 	 
994 	private static final String TEST_NO_QUOTE_ATTR_WITH_EL = 
995 			"<tag:if something=${something} >  <a href=url >foo</a> </tag:if>";
996 	
997 	private static final String TEST_NO_QUOTE_ATTR_WITH_EXPRESSION = 
998 			"<tag:if something=<%=something%> >  </tag:if>";
999 	
1000 	/**
1001 	 * same as {@link #TEST_NO_QUOTE_ATTR_WITH_EXPRESSION} only expression is not 
1002 	 * properly closed
1003 	 */
1004 	private static final String TEST_NO_QUOTE_ATTR_WITH_MALFORMED_EXPR = 
1005 			"<tag:if something=<%=something >  </tag:if>";
1006 	
1007 	private static final String TEST_NO_QUOTE_ATTR_WITH_SCRIPTLET = 
1008 			"<tag:if something=<% String a = \"1\";%>x >  </tag:if>";
1009 	
1010 	
1011 	private static final String TEST_NO_QUOTE_ATTR_WITH_DOLLAR =
1012 			"<tag:if something=${something >  <a href=${ >foo</a> </tag:if>";
1013 	
1014 	private static final String TEST_NO_QUOTE_ATTR_WITH_HASH =
1015 			"<tag:if something=#{something >  <a href=#{url} >foo</a> </tag:if>";
1016 	
1017 	private static final String TEST_UNCLOSED_SIMPLE =
1018 			"<tag:someTag> <tag:if someting=\"x\" > </tag:someTag>";
1019 	
1020 	/**
1021 	 * someTag is closed just once
1022 	 */
1023 	private static final String TEST_UNCLOSED_MULTIPLE_LEVELS = 
1024 			"<tag:x> <tag:someTag> <tag:someTag someting=\"x\" > </tag:someTag> </tag:x>";
1025 	
1026 	/**
1027 	 * nested empty tags
1028 	 */
1029 	private static final String TEST_MULTIPLE_EMPTY_TAGS = 
1030 			"<html> <a1> <a2/> <b/> </a1> </html>"; 
1031 	
1032 	
1033 	/**
1034 	 * multiple nested tags with some tags unclosed
1035 	 */
1036 	private static final String TEST_MULTIPLE_NESTED_TAGS = 
1037 			"<html> <a1> <a2> <a3> </a2> </a1> <b/> <a4/> </html>"; 
1038 	
1039 	/**
1040 	 * </x> will close before </a>, thus leaving <a> to remain unclosed 
1041 	 */
1042 	private static final String TEST_UNCLOSED_END_AFTER_PARENT_CLOSE = 
1043 			"<x> <a> <b> <b> </x> </a> aa </x> bb </x>";
1044 	
1045 	/**
1046 	 * </z> is just a dangling closing tag not matching any parent. The parser should
1047 	 * disregard it
1048 	 */
1049 	private static final String TEST_UNCLOSED_UNMATCHED_CLOSING_TAG = 
1050 			"<x> <a> <b> <b> </z> </a> </x>";
1051 	
1052 	/**
1053 	 * First <a> tag does not close. The first closing of </a> will match the 
1054 	 * second opening of a. Another rogue </z> is there for testing compliance
1055 	 */
1056 	private static final String TEST_UNCLOSED_START_TAG_WITH_UNMATCHED_CLOSE =
1057 			"<a> <x> <a> <b> <b> </z> </a> </x>";
1058 	
1059 	private static final String TEST_UNCLOSED_END_OF_DOC = 
1060 			"<tag:x> <tag:y>";
1061 	
1062 	private static final String TEST_UNCLOSED_NO_QUOTE_ATTR =
1063 			"<tag:someTag> <tag:if someting=x > </tag:someTag>";
1064 	
1065 	
1066     public static junit.framework.Test suite() {
1067         return new junit.framework.JUnit4TestAdapter(JspDocStyleTest.class);
1068     }
1069 }