/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dom.range;
import java.io.StringReader;
import org.apache.xerces.dom.DocumentImpl;
import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ranges.Range;
import org.xml.sax.InputSource;
import dom.Writer;
/**
* 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.
*
* @version $Id: Test.java 447697 2006-09-19 03:08:27Z mrglavas $
*/
public class Test {
static final boolean DEBUG = false;
static boolean fStdOut = 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);
}
if (args.length > 1) {
if (args[1].equals("yes")){
fStdOut = true;
}
}
new Test(args[0]);
}
/** Prints the usage. */
private static void printUsage() {
System.err.println("usage: java dom.range.Test (option) (stdout)");
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");
System.err.println("stdout:");
System.err.println(" yes print to standard output");
System.err.println(" no don't print any messages to standard output [default]");
} // 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("Done.");
}
else {
System.out.println("*** ONE OR MORE TESTS FAILED! ***");
System.exit(1);
}
} else {
performTest(arg);
}
}
public boolean performTest(String arg) {
boolean passed = true;
try {
Writer writer = new Writer(false);
DOMParser parser = new DOMParser();
if (!arg.equals("delete2") && !arg.equals("insert2")) {
if (fStdOut) System.out.println("\n*************** Test == "+arg+" ***************");
for (int i = 0; i < tests.length; i++) {
if (fStdOut) System.out.println("\n\nTest["+i+"]");
if (fStdOut) 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());
}
}
if (fStdOut) System.out.println("range.toString="+range.toString());
DocumentFragment frag = null;
if (arg.equals("surround")) {
try {
if (fStdOut) System.out.println("surroundNode="+surroundNode);
range.surroundContents(surroundNode);
} catch (org.w3c.dom.ranges.RangeException e) {
if (fStdOut) System.out.println(e);
}
String result = toString(document);
if (fStdOut) System.out.println("After surround: document="+result+":");
if (!result.equals(surroundResult[i])) {
if (fStdOut) System.out.println("Should be: document="+surroundResult[i]+":");
passed = false;
if (fStdOut) System.out.println("Test FAILED!");
if (fStdOut) System.out.println("*** Surround document Test["+i+"] FAILED!");
}
}
if (arg.equals("insert")) {
range.insertNode(document.createTextNode(INSERT));
String result = toString(document);
if (fStdOut) System.out.println("After insert: document="+result+":");
if (!result.equals(insertResult[i])) {
if (fStdOut) System.out.println("Should be: document="+insertResult[i]+":");
passed = false;
if (fStdOut) System.out.println("Test FAILED!");
if (fStdOut) System.out.println("*** Insert document Test["+i+"] FAILED!");
}
} else
if (arg.equals("delete")) {
range.deleteContents();
String result = toString(document);
if (fStdOut) System.out.println("After delete:"+result+":");
if (!result.equals(deleteResult[i])) {
if (fStdOut) System.out.println("Should be: document="+deleteResult[i]+":");
passed = false;
if (fStdOut) System.out.println("Test FAILED!");
if (fStdOut) System.out.println("*** Delete document Test["+i+"] FAILED!");
}
}
else
if (arg.equals("extract")) {
frag = range.extractContents();
//range.insertNode(document.createTextNode("^"));
String result = toString(document);
if (fStdOut) System.out.println("After extract: document="+result+":");
if (!result.equals(deleteResult[i])) {
if (fStdOut) System.out.println("Should be: document="+deleteResult[i]+":");
passed = false;
if (fStdOut) System.out.println("*** Extract document Test["+i+"] FAILED!");
}
String fragResult = toString(frag);
if (fStdOut) System.out.println("After extract: fragment="+fragResult+":");
if (!fragResult.equals(extractResult[i])) {
if (fStdOut) System.out.println("Should be: fragment="+extractResult[i]+":");
passed = false;
if (fStdOut) System.out.println("*** Extract Fragment Test["+i+"] FAILED!");
}
}
else
if (arg.equals("clone")) {
frag = range.cloneContents();
String fragResult = toString(frag);
if (fStdOut) System.out.println("After clone: fragment="+fragResult);
if (!fragResult.equals(extractResult[i])) {
if (fStdOut) System.out.println("Should be: fragment="+extractResult[i]+":");
passed = false;
if (fStdOut) System.out.println("*** Clone Fragment Test["+i+"] FAILED!");
}
}
}
} else
if (arg.equals("insert2")) {
if (fStdOut) System.out.println("\n*************** Test == "+arg+" ***************");
for (int i = 0; i < 4; i++) {
if (fStdOut) System.out.println("\n\nTest["+i+"]");
if (fStdOut) 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);
}
//if (fStdOut) System.out.println("range: start1=="+range.getStartContainer());
//root.insertBefore(document.createTextNode("YES!"), root.getFirstChild());
//if (fStdOut) System.out.println("range: start2=="+range.getStartContainer());
if (DEBUG) if (fStdOut) System.out.println("before insert start="+range.getStartOffset());
if (DEBUG) if (fStdOut) System.out.println("before insert end="+range.getEndOffset());
rangei.insertNode(document.createTextNode(INSERTED_TEXT));
if (DEBUG) if (fStdOut) System.out.println("after insert start="+range.getStartOffset());
if (DEBUG) if (fStdOut) System.out.println("after insert end="+range.getEndOffset());
String result = toString(document);
if (fStdOut) System.out.println("After insert2: document="+result+":");
if (!result.equals(rangeInsertResult[i])) {
if (fStdOut) System.out.println("Should be: document="+rangeInsertResult[i]+":");
passed = false;
if (fStdOut) System.out.println("Test FAILED!");
if (fStdOut) System.out.println("*** Delete Ranges document Test["+i+"] FAILED!");
}
}
} else
if (arg.equals("delete2")) {
//
// Range Deletion, acting upon another range.
//
if (fStdOut) System.out.println("\n*************** Test == "+arg+" ***************");
for (int i = 0; i < rangeDelete.length; i++) {
if (fStdOut) System.out.println("\n\nTest["+i+"]");
if (fStdOut) 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) {
if (fStdOut) System.out.println("BEFORE deleteContents()");
if (fStdOut) System.out.println("ranged: startc="+ranged.getStartContainer());
if (fStdOut) System.out.println("ranged: starto="+ranged.getStartOffset());
if (fStdOut) System.out.println("ranged: endc="+ranged.getEndContainer());
if (fStdOut) System.out.println("ranged: endo="+ranged.getEndOffset());
if (fStdOut) System.out.println("range: startc="+range.getStartContainer());
if (fStdOut) System.out.println("range: starto="+range.getStartOffset());
if (fStdOut) System.out.println("range: endc="+range.getEndContainer());
if (fStdOut) System.out.println("range: endo="+range.getEndOffset());
}
ranged.deleteContents();
String result = null;
if (DEBUG) {
if (fStdOut) System.out.println("AFTER deleteContents()");
result = toString(document);
if (fStdOut) System.out.println("ranged: startc="+ranged.getStartContainer());
if (fStdOut) System.out.println("ranged: starto="+ranged.getStartOffset());
if (fStdOut) System.out.println("ranged: endc="+ranged.getEndContainer());
if (fStdOut) System.out.println("ranged: endo="+ranged.getEndOffset());
if (fStdOut) System.out.println("range: startc="+range.getStartContainer());
if (fStdOut) System.out.println("range: starto="+range.getStartOffset());
if (fStdOut) System.out.println("range: endc="+range.getEndContainer());
if (fStdOut) System.out.println("range: endo="+range.getEndOffset());
}
ranged.insertNode(document.createTextNode("^"));
result = toString(document);
if (fStdOut) System.out.println("After delete2: document="+result+":");
if (!result.equals(rangeDeleteResult[i])) {
if (fStdOut) System.out.println("Should be: document="+rangeDeleteResult[i]+":");
passed = false;
if (fStdOut) System.out.println("Test FAILED!");
if (fStdOut) 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) if (fStdOut) 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("<");
break;
}
case '>': {
str.append(">");
break;
}
case '&': {
str.append("&");
break;
}
case '"': {
str.append(""");
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
}