blob: 4e57ef1bfa3fff32d87d872e3befb3bd979d81b4 [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xerces" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, International
* Business Machines, Inc., http://www.apache.org. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package dom.range;
import org.apache.xerces.parsers.*;
import org.apache.xerces.dom.*;
import org.apache.xerces.dom.DocumentImpl;
import org.w3c.dom.*;
import org.w3c.dom.Element;
import org.w3c.dom.range.*;
import org.w3c.dom.range.RangeException;
import java.io.*;
import dom.DOMWriter;
import org.xml.sax.InputSource;
/** This RangeTest tests all of the cases delineated as examples
* in the DOM Level 2 Range specification, and a few others.
* <p>These do not by any means completely test the API and
* corner cases.
*/
public class Test {
static final boolean DEBUG = false;
static final String [] tests = {
"<FOO>AB<MOO>CD</MOO>CD</FOO>",
"<FOO>A<MOO>BC</MOO>DE</FOO>",
"<FOO>XY<BAR>ZW</BAR>Q</FOO>",
"<FOO><BAR1>AB</BAR1><BAR2/><BAR3>CD</BAR3></FOO>",
"<A><B><M/><C><D/><E/><F/><HELLO/></C><N/><O/></B>"+
"<Z><X/><Y/></Z>"+
"<G/><Q><V/><W/></Q></A>"
};
static final String [] deleteResult = {
"<FOO>ACD</FOO>",
"<FOO>A<MOO>B</MOO>E</FOO>",
"<FOO>X<BAR>W</BAR>Q</FOO>",
"<FOO><BAR1>A</BAR1><BAR3>D</BAR3></FOO>",
"<A><B><M></M><C><D></D></C></B><Q><W></W></Q></A>"
};
static final String [] extractResult = {
"B<MOO>CD</MOO>",
"<MOO>C</MOO>D",
"Y<BAR>Z</BAR>",
"<BAR1>B</BAR1><BAR2></BAR2><BAR3>C</BAR3>",
"<B><C><E></E><F></F><HELLO></HELLO></C>"+
"<N></N><O></O></B><Z><X></X><Y></Y></Z><G></G><Q><V></V></Q>"
};
static final String INSERT="***";
static final String [] insertResult = {
"<FOO>A"+INSERT+"B<MOO>CD</MOO>CD</FOO>",
"<FOO>A<MOO>B"+INSERT+"C</MOO>DE</FOO>",
"<FOO>X"+INSERT+"Y<BAR>ZW</BAR>Q</FOO>",
"<FOO><BAR1>A"+INSERT+"B</BAR1><BAR2></BAR2><BAR3>CD</BAR3></FOO>",
"<A><B><M></M><C><D></D>"+INSERT+"<E></E><F></F><HELLO></HELLO></C>"+
"<N></N><O></O></B><Z><X></X><Y></Y></Z><G></G><Q><V></V><W></W></Q></A>"
};
static final String SURROUND="SURROUND";
static final String [] surroundResult = {
"<FOO>A<"+SURROUND+">B<MOO>CD</MOO>C</"+SURROUND+">D</FOO>",
"<FOO>A<MOO>B<"+SURROUND+">C</"+SURROUND+"></MOO>DE</FOO>",
"<FOO>X<"+SURROUND+">Y<BAR>ZW</BAR></"+SURROUND+">Q</FOO>",
"<FOO><BAR1>AB</BAR1><"+SURROUND+"><BAR2></BAR2></"+SURROUND+"><BAR3>CD</BAR3></FOO>",
"<A><B><M></M><C><D></D><E></E><F></F><HELLO></HELLO></C>"+
"<N></N><O></O></B><Z><"+SURROUND+"><X></X><Y></Y></"+SURROUND+"></Z>"+
"<G></G><Q><V></V><W></W></Q></A>"
};
static final String [] rangeDelete = {
"<P>Abcd efgh The Range ijkl</P>",
"<p>Abcd efgh The Range ijkl</p>",
"<P>ABCD efgh The <EM>Range</EM> ijkl</P>",
"<P>Abcd efgh The Range ijkl</P>",
"<P>Abcd <EM>efgh The Range ij</EM>kl</P>"
};
//
static final String [] rangeDeleteResult = {
"<P>Abcd ^Range ijkl</P>",
"<p>Abcd ^kl</p>",
"<P>ABCD ^<EM>ange</EM> ijkl</P>",
"<P>Abcd ^he Range ijkl</P>",
"<P>Abcd ^kl</P>"
};
static final String INSERT2="<P>Abcd efgh XY blah ijkl</P>";
static final String INSERTED_TEXT = "INSERTED TEXT";
static final String [] rangeInsertResult = {
"<P>Abcd efgh INSERTED TEXTXY blah ijkl</P>",
"<P>Abcd efgh XINSERTED TEXTY blah ijkl</P>",
"<P>Abcd efgh XYINSERTED TEXT blah ijkl</P>",
"<P>Abcd efgh XY blahINSERTED TEXT ijkl</P>"
};
public static void main(String args[]) {
// is there anything to do?
if ( args.length == 0 ) {
printUsage();
System.exit(1);
}
new Test(args[0]);
}
/** Prints the usage. */
private static void printUsage() {
System.err.println("usage: java dom.range.Test (options) ...");
System.err.println();
System.err.println("options:");
System.err.println(" all all tests");
System.err.println(" delete delete test");
System.err.println(" extract extract test");
System.err.println(" clone clone test");
System.err.println(" insert insert test");
System.err.println(" surround surround test");
System.err.println(" insert2 insert mutation test");
System.err.println(" delete2 delete mutation test");
} // printUsage()
public Test(String arg) {
if (arg.equals("all")) {
boolean all = false;
all = performTest("delete");
all = performTest("extract")&&all;
all = performTest("clone")&&all;
all = performTest("insert")&&all;
all = performTest("surround")&&all;
all = performTest("insert2")&&all;
all = performTest("delete2")&&all;
if (all)
System.out.println("*** ALL TESTS PASSED! ***");
else
System.out.println("*** ONE OR MORE TESTS FAILED! ***");
} else {
performTest(arg);
}
}
public boolean performTest(String arg) {
boolean passed = true;
try {
DOMWriter writer = new DOMWriter(false);
DOMParser parser = new DOMParser();
if (!arg.equals("delete2") && !arg.equals("insert2")) {
System.out.println("\n*************** Test == "+arg+" ***************");
for (int i = 0; i < tests.length; i++) {
System.out.println("\n\nTest["+i+"]");
System.out.println("\nBefore "+arg+": document="+tests[i]+":");
parser.parse(new InputSource(new StringReader(tests[i])));
DocumentImpl document = (DocumentImpl)parser.getDocument();
Range range = document.createRange();
Node root = document.getDocumentElement();
boolean surround = false;
Node surroundNode=document.createElement(SURROUND);
if (arg.equals("surround")) {
surround = true;
}
if (i == 0) {
range.setStart(root.getFirstChild(), 1);
range.setEndBefore(root.getLastChild());
if (surround)
range.setEnd(root.getLastChild(),1);
}
else if (i == 1) {
Node n1 = root.getFirstChild().getNextSibling().
getFirstChild();
range.setStart(n1, 1);
range.setEnd(root.getLastChild(), 1);
if (surround)
range.setEnd(n1,2);
}
else if (i == 2) {
range.setStart(root.getFirstChild(), 1);
Node n2 = root.getFirstChild().getNextSibling().getFirstChild();
range.setEnd(n2, 1);
if (surround)
range.setEndBefore(root.getLastChild());
}
else if (i == 3) {
Node n3 = root.getFirstChild().getFirstChild();
range.setStart(n3, 1);
range.setEnd(root.getLastChild().getFirstChild(), 1);
if (surround) {
range.selectNode(root.getFirstChild().getNextSibling());
}
}
else if (i == 4) {
Node n4 = root.getFirstChild().getFirstChild().getNextSibling().getFirstChild();
range.setStartAfter(n4);
range.setEndAfter(root.getLastChild().getFirstChild());
if (surround) {
range.selectNodeContents(root.getFirstChild().getNextSibling());
}
}
System.out.println("range.toString="+range.toString());
DocumentFragment frag = null;
if (arg.equals("surround")) {
try {
System.out.println("surroundNode="+surroundNode);
range.surroundContents(surroundNode);
} catch (org.w3c.dom.range.RangeException e) {
System.out.println(e);
}
String result = toString(document);
System.out.println("After surround: document="+result+":");
if (!result.equals(surroundResult[i])) {
System.out.println("Should be: document="+surroundResult[i]+":");
passed = false;
System.out.println("Test FAILED!");
System.out.println("*** Surround document Test["+i+"] FAILED!");
}
}
if (arg.equals("insert")) {
range.insertNode(document.createTextNode(INSERT));
String result = toString(document);
System.out.println("After insert: document="+result+":");
if (!result.equals(insertResult[i])) {
System.out.println("Should be: document="+insertResult[i]+":");
passed = false;
System.out.println("Test FAILED!");
System.out.println("*** Insert document Test["+i+"] FAILED!");
}
} else
if (arg.equals("delete")) {
range.deleteContents();
String result = toString(document);
System.out.println("After delete:"+result+":");
if (!result.equals(deleteResult[i])) {
System.out.println("Should be: document="+deleteResult[i]+":");
passed = false;
System.out.println("Test FAILED!");
System.out.println("*** Delete document Test["+i+"] FAILED!");
}
}
else
if (arg.equals("extract")) {
frag = range.extractContents();
//range.insertNode(document.createTextNode("^"));
String result = toString(document);
System.out.println("After extract: document="+result+":");
if (!result.equals(deleteResult[i])) {
System.out.println("Should be: document="+deleteResult[i]+":");
passed = false;
System.out.println("*** Extract document Test["+i+"] FAILED!");
}
String fragResult = toString(frag);
System.out.println("After extract: fragment="+fragResult+":");
if (!fragResult.equals(extractResult[i])) {
System.out.println("Should be: fragment="+extractResult[i]+":");
passed = false;
System.out.println("*** Extract Fragment Test["+i+"] FAILED!");
}
}
else
if (arg.equals("clone")) {
frag = range.cloneContents();
String fragResult = toString(frag);
System.out.println("After clone: fragment="+fragResult);
if (!fragResult.equals(extractResult[i])) {
System.out.println("Should be: fragment="+extractResult[i]+":");
passed = false;
System.out.println("*** Clone Fragment Test["+i+"] FAILED!");
}
}
}
} else
if (arg.equals("insert2")) {
System.out.println("\n*************** Test == "+arg+" ***************");
for (int i = 0; i < 4; i++) {
System.out.println("\n\nTest["+i+"]");
System.out.println("\nBefore "+arg+": document="+INSERT2+":");
parser.parse(new InputSource(new StringReader(INSERT2)));
DocumentImpl document = (DocumentImpl)parser.getDocument();
Node root = document.getDocumentElement();
Range range = document.createRange();
range.setStart(root.getFirstChild(),11);
range.setEnd(root.getFirstChild(),18);
Range rangei = document.createRange();
if (i == 0) {
rangei.setStart(root.getFirstChild(), 10);
rangei.setEnd(root.getFirstChild(), 10);
}
if (i == 1) {
rangei.setStart(root.getFirstChild(), 11);
rangei.setEnd(root.getFirstChild(), 11);
}
if (i == 2) {
rangei.setStart(root.getFirstChild(), 12);
rangei.setEnd(root.getFirstChild(), 12);
}
if (i == 3) {
rangei.setStart(root.getFirstChild(), 17);
rangei.setEnd(root.getFirstChild(), 17);
}
//System.out.println("range: start1=="+range.getStartContainer());
//root.insertBefore(document.createTextNode("YES!"), root.getFirstChild());
//System.out.println("range: start2=="+range.getStartContainer());
if (DEBUG) System.out.println("before insert start="+range.getStartOffset());
if (DEBUG) System.out.println("before insert end="+range.getEndOffset());
rangei.insertNode(document.createTextNode(INSERTED_TEXT));
if (DEBUG) System.out.println("after insert start="+range.getStartOffset());
if (DEBUG) System.out.println("after insert end="+range.getEndOffset());
String result = toString(document);
System.out.println("After insert2: document="+result+":");
if (!result.equals(rangeInsertResult[i])) {
System.out.println("Should be: document="+rangeInsertResult[i]+":");
passed = false;
System.out.println("Test FAILED!");
System.out.println("*** Delete Ranges document Test["+i+"] FAILED!");
}
}
} else
if (arg.equals("delete2")) {
//
// Range Deletion, acting upon another range.
//
System.out.println("\n*************** Test == "+arg+" ***************");
for (int i = 0; i < rangeDelete.length; i++) {
System.out.println("\n\nTest["+i+"]");
System.out.println("\nBefore "+arg+": document="+rangeDelete[i]+":");
parser.parse(new InputSource(new StringReader(rangeDelete[i])));
DocumentImpl document = (DocumentImpl)parser.getDocument();
Range range = document.createRange();
Range ranged = document.createRange();
Node root = document.getDocumentElement();
boolean surround = false;
Node surroundNode=document.createElement(SURROUND);
if (arg.equals("surround")) {
surround = true;
}
if (i == 0) {
ranged.setStart(root.getFirstChild(), 5);
ranged.setEnd(root.getFirstChild(), 14);
range.setStart(root.getFirstChild(), 11);
range.setEnd(root.getFirstChild(), 19);
}
else if (i == 1) {
ranged.setStart(root.getFirstChild(), 5);
ranged.setEnd(root.getFirstChild(), 22);
range.setStart(root.getFirstChild(), 11);
range.setEnd(root.getFirstChild(), 21);
}
else if (i == 2) {
ranged.setStart(root.getFirstChild(), 5);
ranged.setEnd(root.getFirstChild().getNextSibling()
.getFirstChild(), 1);
range.setStart(root.getFirstChild(), 11);
range.setEndAfter(root.getFirstChild().getNextSibling()
.getFirstChild());
}
else if (i == 3) {
ranged.setStart(root.getFirstChild(), 5);
ranged.setEnd(root.getFirstChild(), 11);
range.setStart(root.getFirstChild(), 11);
range.setEnd(root.getFirstChild(), 21);
}
else if (i == 4) {
ranged.selectNode(root.getFirstChild().getNextSibling());
range.setStart(root.getFirstChild().getNextSibling()
.getFirstChild(), 6);
range.setEnd(root.getFirstChild().getNextSibling()
.getFirstChild(), 15);
}
DocumentFragment frag = null;
if (arg.equals("delete2")) {
if (DEBUG) {
System.out.println("BEFORE deleteContents()");
System.out.println("ranged: startc="+ranged.getStartContainer());
System.out.println("ranged: starto="+ranged.getStartOffset());
System.out.println("ranged: endc="+ranged.getEndContainer());
System.out.println("ranged: endo="+ranged.getEndOffset());
System.out.println("range: startc="+range.getStartContainer());
System.out.println("range: starto="+range.getStartOffset());
System.out.println("range: endc="+range.getEndContainer());
System.out.println("range: endo="+range.getEndOffset());
}
ranged.deleteContents();
String result = null;
if (DEBUG) {
System.out.println("AFTER deleteContents()");
result = toString(document);
System.out.println("ranged: startc="+ranged.getStartContainer());
System.out.println("ranged: starto="+ranged.getStartOffset());
System.out.println("ranged: endc="+ranged.getEndContainer());
System.out.println("ranged: endo="+ranged.getEndOffset());
System.out.println("range: startc="+range.getStartContainer());
System.out.println("range: starto="+range.getStartOffset());
System.out.println("range: endc="+range.getEndContainer());
System.out.println("range: endo="+range.getEndOffset());
}
ranged.insertNode(document.createTextNode("^"));
result = toString(document);
System.out.println("After delete2: document="+result+":");
if (!result.equals(rangeDeleteResult[i])) {
System.out.println("Should be: document="+rangeDeleteResult[i]+":");
passed = false;
System.out.println("Test FAILED!");
System.out.println("*** Delete Ranges document Test["+i+"] FAILED!");
}
}
}
}
}
catch (org.xml.sax.SAXParseException spe) {
passed = false;
}
catch (org.xml.sax.SAXException se) {
if (se.getException() != null)
se.getException().printStackTrace(System.err);
else
se.printStackTrace(System.err);
passed = false;
}
catch (Exception e) {
e.printStackTrace(System.err);
passed = false;
}
if (!passed) System.out.println("*** The "+arg+" Test FAILED! ***");
return passed;
}
StringBuffer sb;
boolean canonical = true;
String toString(Node node) {
sb = new StringBuffer();
return print(node);
}
/** Prints the specified node, recursively. */
public String print(Node node) {
// is there anything to do?
if ( node == null ) {
return sb.toString();
}
int type = node.getNodeType();
switch ( type ) {
// print document
case Node.DOCUMENT_NODE: {
return print(((Document)node).getDocumentElement());
//out.flush();
//break;
}
// print element with attributes
case Node.ELEMENT_NODE: {
sb.append('<');
sb.append(node.getNodeName());
Attr attrs[] = sortAttributes(node.getAttributes());
for ( int i = 0; i < attrs.length; i++ ) {
Attr attr = attrs[i];
sb.append(' ');
sb.append(attr.getNodeName());
sb.append("=\"");
sb.append(normalize(attr.getNodeValue()));
sb.append('"');
}
sb.append('>');
NodeList children = node.getChildNodes();
if ( children != null ) {
int len = children.getLength();
for ( int i = 0; i < len; i++ ) {
print(children.item(i));
}
}
break;
}
// handle entity reference nodes
case Node.ENTITY_REFERENCE_NODE: {
if ( canonical ) {
NodeList children = node.getChildNodes();
if ( children != null ) {
int len = children.getLength();
for ( int i = 0; i < len; i++ ) {
print(children.item(i));
}
}
} else {
sb.append('&');
sb.append(node.getNodeName());
sb.append(';');
}
break;
}
// print cdata sections
case Node.CDATA_SECTION_NODE: {
if ( canonical ) {
sb.append(normalize(node.getNodeValue()));
} else {
sb.append("<![CDATA[");
sb.append(node.getNodeValue());
sb.append("]]>");
}
break;
}
// print text
case Node.TEXT_NODE: {
sb.append(normalize(node.getNodeValue()));
break;
}
// print processing instruction
case Node.PROCESSING_INSTRUCTION_NODE: {
sb.append("<?");
sb.append(node.getNodeName());
String data = node.getNodeValue();
if ( data != null && data.length() > 0 ) {
sb.append(' ');
sb.append(data);
}
sb.append("?>");
break;
}
// handle entity reference nodes
case Node.DOCUMENT_FRAGMENT_NODE: {
NodeList children = node.getChildNodes();
if ( children != null ) {
int len = children.getLength();
for ( int i = 0; i < len; i++ ) {
print(children.item(i));
}
}
break;
}
}
if ( type == Node.ELEMENT_NODE ) {
sb.append("</");
sb.append(node.getNodeName());
sb.append('>');
}
return sb.toString();
} // print(Node)
/** Returns a sorted list of attributes. */
protected Attr[] sortAttributes(NamedNodeMap attrs) {
int len = (attrs != null) ? attrs.getLength() : 0;
Attr array[] = new Attr[len];
for ( int i = 0; i < len; i++ ) {
array[i] = (Attr)attrs.item(i);
}
for ( int i = 0; i < len - 1; i++ ) {
String name = array[i].getNodeName();
int index = i;
for ( int j = i + 1; j < len; j++ ) {
String curName = array[j].getNodeName();
if ( curName.compareTo(name) < 0 ) {
name = curName;
index = j;
}
}
if ( index != i ) {
Attr temp = array[i];
array[i] = array[index];
array[index] = temp;
}
}
return (array);
} // sortAttributes(NamedNodeMap):Attr[]
/** Normalizes the given string. */
protected String normalize(String s) {
StringBuffer str = new StringBuffer();
int len = (s != null) ? s.length() : 0;
for ( int i = 0; i < len; i++ ) {
char ch = s.charAt(i);
switch ( ch ) {
case '<': {
str.append("&lt;");
break;
}
case '>': {
str.append("&gt;");
break;
}
case '&': {
str.append("&amp;");
break;
}
case '"': {
str.append("&quot;");
break;
}
case '\r':
case '\n': {
if ( canonical ) {
str.append("&#");
str.append(Integer.toString(ch));
str.append(';');
break;
}
// else, default append char
}
default: {
str.append(ch);
}
}
}
return (str.toString());
} // normalize(String):String
}