// HTMLParser Library $Name: v1_6 $ - A java-based parser for HTML
// http://sourceforge.org/projects/htmlparser
// Copyright (C) 2004 Somik Raha
//
// Revision Control Information
//
// $Source: /cvsroot/htmlparser/htmlparser/src/org/htmlparser/tests/ParserTestCase.java,v $
// $Author: derrickoswald $
// $Date: 2006/04/17 23:45:11 $
// $Revision: 1.53 $
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
package org.htmlparser.tests;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
import junit.framework.TestCase;
import org.htmlparser.Attribute;
import org.htmlparser.Node;
import org.htmlparser.Parser;
import org.htmlparser.Tag;
import org.htmlparser.Text;
import org.htmlparser.lexer.Lexer;
import org.htmlparser.lexer.Page;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.tags.FormTag;
import org.htmlparser.tags.InputTag;
import org.htmlparser.util.DefaultParserFeedback;
import org.htmlparser.util.NodeIterator;
import org.htmlparser.util.ParserException;
import org.htmlparser.util.ParserUtils;
public class ParserTestCase extends TestCase {
static boolean mCaseInsensitiveComparisons = false;
protected Parser parser;
protected Node node [];
protected int nodeCount;
protected Lexer mLexer;
public ParserTestCase(String name) {
super(name);
}
public void testFake ()
{
}
protected void parse(String response) throws ParserException {
createParser(response,10000);
parseNodes();
}
protected void createParser(String inputHTML) {
mLexer = new Lexer (new Page (inputHTML));
parser = new Parser(mLexer, new DefaultParserFeedback(DefaultParserFeedback.QUIET));
node = new Node[40];
}
protected void createParser(String inputHTML,int numNodes)
{
Lexer lexer = new Lexer (inputHTML);
parser = new Parser (lexer, new DefaultParserFeedback(DefaultParserFeedback.QUIET));
node = new Node[numNodes];
}
protected void createParser(String inputHTML, String url) {
Lexer lexer = new Lexer (inputHTML);
lexer.getPage ().setUrl (url);
parser = new Parser (lexer, new DefaultParserFeedback(DefaultParserFeedback.QUIET));
node = new Node[40];
}
protected void createParser(String inputHTML, String url,int numNodes) {
Lexer lexer = new Lexer (inputHTML);
lexer.getPage ().setUrl (url);
parser = new Parser (lexer, new DefaultParserFeedback(DefaultParserFeedback.QUIET));
node = new Node[numNodes];
}
public Parser getParser ()
{
return (parser);
}
public void setParser (Parser parser)
{
this.parser = parser;
}
public void assertStringEquals(String message, String expected,
String actual) {
String mismatchInfo = "";
if (expected.length() < actual.length()) {
mismatchInfo = "\n\nACTUAL result has "+(actual.length()-expected.length())+" extra characters at the end. They are :";
int limit = Math.min (expected.length() + 10, actual.length());
for (int i = expected.length(); i < limit; i++)
mismatchInfo += ("\nPosition : " + i + " , Code = " + (int) actual.charAt(i));
if (limit != actual.length())
mismatchInfo += "\netc.";
} else if(expected.length() > actual.length()) {
mismatchInfo = "\n\nEXPECTED result has "+(expected.length()-actual.length())+" extra characters at the end. They are :";
int limit = Math.min (actual.length() + 10, expected.length());
for (int i = actual.length(); i < expected.length(); i++)
mismatchInfo += ("\nPosition : " + i + " , Code = " + (int) expected.charAt(i));
if (limit != expected.length ())
mismatchInfo += "\netc.";
}
for (int i = 0; i < expected.length(); i++) {
if (
(expected.length() != actual.length() &&
(
i >= (expected.length()-1 ) ||
i >= (actual.length()-1 )
)
) ||
(mCaseInsensitiveComparisons && Character.toUpperCase (actual.charAt(i)) != Character.toUpperCase (expected.charAt(i))) ||
(!mCaseInsensitiveComparisons && (actual.charAt(i) != expected.charAt(i)))
) {
StringBuffer errorMsg = new StringBuffer();
errorMsg.append(
message +mismatchInfo + " \nMismatch of strings at char posn " + i +
" \n\nString Expected upto mismatch = " +
expected.substring(0, i) +
" \n\nString Actual upto mismatch = " +
actual.substring(0, i)
);
if (i<expected.length())
errorMsg.append(
" \n\nString Expected MISMATCH CHARACTER = "+
expected.charAt(i) + ", code = " +
(int) expected.charAt(i)
);
if (i<actual.length())
errorMsg.append(
" \n\nString Actual MISMATCH CHARACTER = " +
actual.charAt(i) + ", code = " +
(int) actual.charAt(i)
);
errorMsg.append(
" \n\n**** COMPLETE STRING EXPECTED ****\n" +
expected +
" \n\n**** COMPLETE STRING ACTUAL***\n" + actual
);
System.out.println ("string differs, expected \"" + expected + "\", actual \"" + actual + "\"");
failWithMessage(errorMsg.toString());
}
}
}
public void failWithMessage(String message) {
fail(message);
}
public void parseNodes() throws ParserException{
nodeCount = 0;
for (NodeIterator e = parser.elements();e.hasMoreNodes();)
{
node[nodeCount++] = e.nextNode();
}
}
public void assertNodeCount(int nodeCountExpected) {
StringBuffer msg = new StringBuffer();
for (int i=0;i<nodeCount;i++) {
msg.append(node[i].getClass().getName());
msg.append("-->\n").append(node[i].toHtml()).append("\n");
}
if (nodeCountExpected != nodeCount)
System.out.println ("node count differs, expected " + nodeCountExpected + ", actual " + nodeCount);
assertEquals("Number of nodes parsed didn't match, nodes found were :\n"+msg.toString(),nodeCountExpected,nodeCount);
}
public void parseAndAssertNodeCount(int nodeCountExpected) throws ParserException {
parseNodes();
assertNodeCount(nodeCountExpected);
}
public void assertSameType(String displayMessage, Node expected, Node actual) {
String expectedNodeName = expected.getClass().getName();
String actualNodeName = actual.getClass().getName();
displayMessage =
"The types did not match: Expected "+
expectedNodeName+" \nbut was "+
actualNodeName+"\nEXPECTED XML:"+expected.toHtml()+"\n"+
"ACTUAL XML:"+actual.toHtml()+displayMessage;
assertStringEquals(displayMessage, expectedNodeName, actualNodeName);
}
public void assertTagEquals(String displayMessage, Node expected, Node actual) {
if (expected instanceof Tag) {
Tag expectedTag = (Tag)expected;
Tag actualTag = (Tag)actual;
assertTagNameMatches(displayMessage, expectedTag, actualTag);
assertAttributesMatch(displayMessage, expectedTag, actualTag);
}
}
private void assertTagNameMatches(
String displayMessage,
Tag nextExpectedTag,
Tag nextActualTag) {
String expectedTagName = nextExpectedTag.getTagName();
String actualTagName = nextActualTag.getTagName();
displayMessage = "The tag names did not match: Expected "+expectedTagName+" \nbut was "+actualTagName+displayMessage;
assertStringEquals(displayMessage, expectedTagName, actualTagName);
}
public void assertXmlEquals(String displayMessage, String expected, String actual) throws Exception
{
Node nextExpectedNode;
Node nextActualNode;
Tag tag1;
Tag tag2;
expected = removeEscapeCharacters(expected);
actual = removeEscapeCharacters(actual);
Parser expectedParser = Parser.createParser(expected, null);
Parser resultParser = Parser.createParser(actual, null);
NodeIterator expectedIterator = expectedParser.elements();
NodeIterator actualIterator = resultParser.elements();
displayMessage = createGenericFailureMessage(displayMessage, expected, actual);
nextExpectedNode = null;
nextActualNode = null;
tag1 = null;
tag2 = null;
do {
if (null != tag1)
nextExpectedNode = tag1;
else
nextExpectedNode = getNextNodeUsing (expectedIterator);
if (null != tag2)
nextActualNode = tag2;
else
nextActualNode = getNextNodeUsing (actualIterator);
assertNotNull (nextActualNode);
tag1 = fixIfXmlEndTag (expectedParser.getLexer ().getPage (), nextExpectedNode);
tag2 = fixIfXmlEndTag (resultParser.getLexer ().getPage (), nextActualNode);
assertStringValueMatches(
displayMessage,
nextExpectedNode,
nextActualNode
);
assertSameType(displayMessage, nextExpectedNode, nextActualNode);
assertTagEquals(displayMessage, nextExpectedNode, nextActualNode);
}
while (expectedIterator.hasMoreNodes() || (null != tag1));
assertActualXmlHasNoMoreNodes(displayMessage, actualIterator);
}
private Node getNextNodeUsing(NodeIterator nodeIterator)
throws ParserException {
Node nextNode;
String text=null;
do {
nextNode = nodeIterator.nextNode();
if (nextNode instanceof Text) {
text = nextNode.toPlainTextString().trim();
} else text = null;
}
while (text!=null && text.length()==0);
return nextNode;
}
private void assertStringValueMatches(
String displayMessage, Node expectedNode,Node actualNode) {
String expected = expectedNode.toPlainTextString().trim();
String actual = actualNode.toPlainTextString().trim();
expected = expected.replace('\n', ' ');
actual = actual.replace('\n',' ');
displayMessage = "String value mismatch\nEXPECTED:"+expected+"\nACTUAL:"+actual+displayMessage;
assertStringEquals(displayMessage,expected,actual);
}
private void assertActualXmlHasNoMoreNodes(
String displayMessage,
NodeIterator actualIterator)
throws ParserException {
if (actualIterator.hasMoreNodes()) {
String extraTags = "\nExtra Tags\n**********\n";
do {
extraTags += actualIterator.nextNode().toHtml();
}
while (actualIterator.hasMoreNodes());
displayMessage = "Actual had more data than expected\n"+extraTags+displayMessage;
fail(displayMessage);
}
}
private String createGenericFailureMessage(
String displayMessage,
String expected,
String actual) {
return "\n\n"+displayMessage+"\n\nComplete Xml\n************\nEXPECTED:\n"+expected+"\nACTUAL:\n"+actual;
}
/**
* Return a following tag if node is an empty XML tag.
*/
private Tag fixIfXmlEndTag (Page page, Node node)
{
Tag ret;
ret = null;
if (node instanceof Tag)
{
Tag tag = (Tag)node;
if (tag.isEmptyXmlTag())
{
tag.setEmptyXmlTag (false);
ret = new TagNode (page, tag.getStartPosition (), tag.getEndPosition (), tag.getAttributesEx ());
}
}
return (ret);
}
private void assertAttributesMatch(String displayMessage, Tag expectedTag, Tag actualTag)
{
assertAllExpectedTagAttributesFoundInActualTag(
displayMessage,
expectedTag,
actualTag);
if (expectedTag.getAttributesEx().size() != actualTag.getAttributesEx().size())
assertActualTagHasNoExtraAttributes(displayMessage, expectedTag, actualTag);
}
private void assertActualTagHasNoExtraAttributes(String displayMessage, Tag expectedTag, Tag actualTag)
{
assertStringEquals (displayMessage+"\ntag name", expectedTag.getTagName (), actualTag.getTagName ());
Vector v = actualTag.getAttributesEx ();
for (int i = 1; i < v.size (); i++)
{
Attribute a = (Attribute)v.elementAt (i);
if (a.isWhitespace ())
continue;
String expectedValue = expectedTag.getAttribute (a.getName ());
if (null == expectedValue)
fail("\nActual tag had extra attribute: " + a.getName () + displayMessage);
}
}
private void assertAllExpectedTagAttributesFoundInActualTag(
String displayMessage,
Tag expectedTag,
Tag actualTag)
{
assertStringEquals (displayMessage+"\ntag name", expectedTag.getTagName (), actualTag.getTagName ());
Vector v = actualTag.getAttributesEx ();
for (int i = 1; i < v.size (); i++)
{
Attribute a = (Attribute)v.elementAt (i);
if (a.isWhitespace ())
continue;
String actualValue = actualTag.getAttribute (a.getName ());
String expectedValue = expectedTag.getAttribute (a.getName ());
assertStringEquals(
"\nvalue for attribute " + a.getName () + " in tag "+expectedTag.getTagName()+" expected="+expectedValue+" but was "+actualValue+
"\n\nComplete Tag expected:\n"+expectedTag.toHtml()+
"\n\nComplete Tag actual:\n"+actualTag.toHtml()+
displayMessage,
expectedValue,
actualValue
);
}
}
public static String removeEscapeCharacters(String inputString) {
inputString = ParserUtils.removeChars(inputString,'\r');
inputString = inputString.replace ('\n',' ');
inputString = ParserUtils.removeChars(inputString,'\t');
return inputString;
}
public void assertSuperType(
String message,
Class expectedType,
Object object)
{
String expectedTypeName = expectedType.getName();
String actualTypeName = object.getClass().getName();
if (!expectedType.isAssignableFrom (object.getClass ()))
fail(
message+" should have been of type\n"+
expectedTypeName+
" but was of type \n"+
actualTypeName+"\n and is :"+((Node)object).toHtml()
);
}
public void assertType(
String message,
Class expectedType,
Object object)
{
if (!expectedType.isAssignableFrom (object.getClass ()))
{
String expectedTypeName = expectedType.getName ();
String actualTypeName = object.getClass ().getName ();
if (!actualTypeName.equals (expectedTypeName))
fail(
message + " should have been of type "+
expectedTypeName
+ " but was of type "
+ actualTypeName
+ " and is:"
+ ((Node)object).toHtml()
);
}
}
protected void assertHiddenIDTagPresent(FormTag formTag, String name, String inputTagValue) {
InputTag inputTag = formTag.getInputTag(name);
assertNotNull("Hidden Tag "+name+" should have been there", inputTag);
assertStringEquals("Hidden Tag Contents", inputTagValue, inputTag.getAttribute("VALUE"));
assertStringEquals("Hidden Tag Type", "hidden", inputTag.getAttribute("TYPE"));
}
protected void assertNodeCount(String message, int expectedLength, Node[] nodes) {
if (expectedLength!=nodes.length) {
StringBuffer failMsg = new StringBuffer(message);
failMsg.append("\n");
failMsg.append("Number of nodes expected ").append(expectedLength).append(" \n");
failMsg.append("but was : ");
failMsg.append(nodes.length).append("\n");
failMsg.append("Nodes found are:\n");
for (int i=0;i<nodes.length;i++) {
failMsg.append("Node ").append(i).append(" : ");
failMsg.append(nodes[i].getClass().getName()).append("\n");
failMsg.append(nodes[i].toString()).append("\n\n");
}
fail(failMsg.toString());
}
}
/**
* Mainline for individual test cases.
* @param args Command line arguments. The following options
* are understood:
* <pre>
* -text -- use junit.textui.TestRunner
* -awt -- use junit.awtui.TestRunner
* -swing -- use junit.swingui.TestRunner (default)
* </pre>
* All other options are passed on to the junit framework.
* Decides the test class by examiing the system properties looking
* for a property that starts with "org.htmlparser.tests.", this is
* used as the name of the class (the value is ignored).
* Each class that subclasses ParserTestCase can inherit this mainline
* by adding a static block in their class similar to:
* <pre>
* static
* {
* System.setProperty ("org.htmlparser.tests.ParserTest", "ParserTest");
* }
* </pre>
*/
public static void main(String[] args)
{
String runner;
int i;
String arguments[];
Properties properties;
Enumeration enumeration;
String name;
Class cls;
runner = null;
for (i = 0; (i < args.length) && (null == runner); i++)
{
if (args[i].equalsIgnoreCase ("-text"))
runner = "junit.textui.TestRunner";
else if (args[i].equalsIgnoreCase ("-awt"))
runner = "junit.awtui.TestRunner";
else if (args[i].equalsIgnoreCase ("-swing"))
runner = "junit.swingui.TestRunner";
}
if (null != runner)
{
// remove it from the arguments
arguments = new String[args.length - 1];
System.arraycopy (args, 0, arguments, 0, i - 1);
System.arraycopy (args, i, arguments, i - 1, args.length - i);
args = arguments;
}
else
runner = "junit.swingui.TestRunner";
// find the test class that has registered in the system properties
arguments = args; // default of no class name, works in GUI mode
properties = System.getProperties ();
enumeration = properties.propertyNames ();
while (enumeration.hasMoreElements ())
{
name = (String)enumeration.nextElement ();
if (name.startsWith ("org.htmlparser.tests."))
{
// from http://www.mail-archive.com/commons-user%40jakarta.apache.org/msg02958.html
//
// The problem is within the UI test runners of JUnit. They bring
// with them a custom classloader, which causes the
// LogConfigurationException. Unfortunately Log4j doesn't work
// either.
//
// Solution: Disable "Reload classes every run" or start JUnit with
// command line option -noloading before the name of the Testsuite.
if (true)
{
// append the test class
arguments = new String[args.length + 2];
System.arraycopy (args, 0, arguments, 0, args.length);
arguments[arguments.length - 2] = "-noloading";
arguments[arguments.length - 1] = name;
}
else
{
// append the test class
arguments = new String[args.length + 1];
System.arraycopy (args, 0, arguments, 0, args.length);
arguments[args.length] = name;
}
break; // JUnit only handles one class on the command line
}
}
// invoke main() of the test runner
try
{
cls = Class.forName (runner);
java.lang.reflect.Method method = cls.getDeclaredMethod (
"main", new Class[] { String[].class });
method.invoke (
null,
new Object[] { arguments });
}
catch (Throwable t)
{
System.err.println (
"cannot run unit test ("
+ t.getMessage ()
+ ")");
}
}
}