blob: 953973cc83bbc015d2e711de9ce987734f5ef9f0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2013 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation
*
******************************************************************************/
package org.eclipse.persistence.tools.mapping.tests;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.eclipse.persistence.tools.mapping.ExternalForm;
import org.eclipse.persistence.tools.utility.ClassTools;
import org.junit.Test;
import org.w3c.dom.Node;
import static org.junit.Assert.*;
/**
* This test defines the behavior to test the manipulation of an XML document through an SPI.
*
* @version 2.6
*/
@SuppressWarnings("nls")
public abstract class AbstractExternalFormTests<T extends ExternalForm> {
/**
* Populates the given tester with the appropriate {@link NodeTester}.
*
* @param tester The tester of the node to test
*/
protected abstract void populate(RootNodeTester<T> tester);
/**
* Performs the actual tests on the document for a particular node that is being manipulated by
* an {@link ExternalForm}.
*/
@Test
public final void test() throws Exception {
DefaultRootNodeTester tester = new DefaultRootNodeTester();
populate(tester);
tester.test();
}
/**
* An <code>AttributeNodeTester</code> tests setting and retrieving the value associated with
* an element's attribute.
*/
public interface AttributeNodeTester<T, VALUE> extends PropertyTester<T, VALUE> {
}
/**
* An <code>AttributeNodeTesterRunner</code> tests setting and retrieving the value associated
* with an element's attribute.
* <p>
* <div nowrap>Form: <code><b>&lt;nodeName attributeName="value"/&gt;</b></div>
*/
private class AttributeNodeTesterRunner extends PropertyNodeTesterRunner {
/**
* Creates a new <code>AttributeNodeTesterRunner</code>.
*
* @param tester This object defines a single node to test an attribute node
*/
AttributeNodeTesterRunner(AttributeNodeTester<T, ?> tester) {
super(tester);
}
/**
* {@inheritDoc}
*/
@Override
String displayString() {
return "<" + parentNodeName + " " + getNodeName() + "=\"\">";
}
/**
* {@inheritDoc}
*/
@Override
int getChildrenCount(Node parentNode) {
return parentNode.getAttributes().getLength();
}
/**
* {@inheritDoc}
*/
@Override
Node getNode(Node parentNode) {
return parentNode.getAttributes().getNamedItem(getNodeName());
}
/**
* {@inheritDoc}
*/
@Override
String getNodeValue(Node node) {
return node.getTextContent();
}
}
private class ChildListNodeRunnerAddingController extends Controller {
/**
* {@inheritDoc}
*/
@Override
void log() {
System.out.println("<" + runner.parentNodeName + "><" + runner.tester.getNodeName() + "*> : addition");
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
void test(T form, Node node) {
ChildListNodeTesterRunner runner = (ChildListNodeTesterRunner) this.runner;
// Create a random range within the list of values used to create the child nodes
Random random = new Random();
int count = runner.getDefaultChildrenCount();
int startIndex = random.nextInt(count);
int endIndex = random.nextInt(count);
// Make sure the start and end indices are not the same
while (endIndex == startIndex) {
endIndex = random.nextInt(count);
}
runner.currentChildrenCount = currentChildrenCount;
runner.addRange(startIndex, endIndex);
runner.rangeIndex = runner.ranges.size() - 1;
runner.testInitialState(form, node);
runner.testAdding(form, node);
runner.testReading(form, node);
currentChildrenCount = runner.currentChildrenCount;
}
}
private class ChildListNodeRunnerReadingController extends Controller {
/**
* {@inheritDoc}
*/
@Override
void log() {
System.out.println("<" + runner.parentNodeName + "><" + runner.tester.getNodeName() + "*> : read");
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
void test(T form, Node node) {
ChildListNodeTesterRunner runner = (ChildListNodeTesterRunner) this.runner;
int rangesCount = runner.ranges.size();
// Nothing to read
if (rangesCount == 0) {
return;
}
// Read a range randomly
Random random = new Random();
int rangeIndex = random.nextInt(rangesCount);
runner.rangeIndex = rangeIndex;
runner.currentChildrenCount = currentChildrenCount;
runner.testInitialState(form, node);
runner.testReading(form, node);
currentChildrenCount = runner.currentChildrenCount;
}
}
private class ChildListNodeRunnerRemovingController extends Controller {
/**
* {@inheritDoc}
*/
@Override
void log() {
System.out.println("<" + runner.parentNodeName + "><" + runner.tester.getNodeName() + "*> : removal");
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
void test(T form, Node node) {
ChildListNodeTesterRunner runner = (ChildListNodeTesterRunner) this.runner;
int rangesCount = runner.ranges.size();
// Nothing to read
if (rangesCount == 0) {
return;
}
// Read a range randomly
Random random = new Random();
int rangeIndex = random.nextInt(rangesCount);
runner.rangeIndex = rangeIndex;
runner.currentChildrenCount = currentChildrenCount;
runner.testInitialState(form, node);
runner.testRemoving(form, node);
currentChildrenCount = runner.currentChildrenCount;
}
}
/**
* This <code>ChildListNodeTester</code> tests a form when the node it represents can have zero
* or many child nodes of the same type (i.e. with the same node name).
*/
public interface ChildListNodeTester<T, VALUE, CHILD_VALUE> extends NodeTester<T, VALUE> {
/**
* Adds a new child node to the node represented by the given form.
*
* @param form The external form being tested
* @param value The value used when creating the child node
* @return The external form representing the child node that was added to the node represented
* by the given form
*/
VALUE addChild(T form, CHILD_VALUE value);
/**
* Returns the child node from the node represented by the given form at the given position.
*
* @param form The external form being tested
* @param index The position of the child node to retrieve
* @return The external form representing the child node at the given position
*/
VALUE getChild(T form, int index);
/**
* Returns a list of the children node with the same type (i.e. with the same node name) that
* are children of the node represented by the given form.
*
* @param form The external form being tested
* @return An ordered list based on the sequence of children node
*/
List<VALUE> getChildren(T form);
/**
* Returns the number of children of the node represented by the given form with the same type
* (i.e. with the same node name).
*
* @param form The external form being tested
* @return The count of children of the same type
*/
int getChildrenSize(T form);
/**
* Returns the value that part of the list ({@link #getChildValues()}) and that was used to
* create a child form.
*
* @param childForm The child form from which the value used to create it should be returned
* @return The value retrieved from the child node
*/
CHILD_VALUE getChildValue(VALUE childForm);
/**
* Returns a list of values that will be used to create children of the node represented by
* the form being tested. Each value will be used when calling {@link #addChild(Object, Object)}.
*
* @return A list of values, which should have more than 1 item
*/
List<CHILD_VALUE> getChildValues();
/**
* Removes the child node from the node represented by the given form.
*
* @param form The external form being tested
* @param index The position of the child node within the list of children of the same type
* (i.e. with the same node name)
*/
void removeChild(T form, int index);
}
/**
* A <code>ChildListNodeTesterRunner</code> TODO.
*/
private class ChildListNodeTesterRunner extends NodeTesterRunner {
int currentChildListCount;
int rangeIndex;
List<Integer[]> ranges;
/**
* Creates a new <code>ChildListNodeTesterRunner</code>.
*
* @param tester This object defines a single child node to test
*/
ChildListNodeTesterRunner(ChildListNodeTester<T, ?, ?> tester) {
super(tester);
initialize(tester);
}
void addRange(int startIndex, int endIndex) {
ranges.add(new Integer[] { Math.min(startIndex, endIndex), Math.max(startIndex, endIndex) });
}
private String displayString() {
return "<" + getNodeName() + ">";
}
private List<Node> getChildrenNodes(Node node) {
node = node.getFirstChild();
List<Node> children = new ArrayList<Node>();
while (node != null) {
if (getNodeName().equals(node.getNodeName())) {
children.add(node);
}
node = node.getNextSibling();
}
return children;
}
@SuppressWarnings("unchecked")
int getDefaultChildrenCount() {
ChildListNodeTester<T, Object, Object> tester = (ChildListNodeTester<T, Object, Object>) this.tester;
return tester.getChildValues().size();
}
private void initialize(ChildListNodeTester<T, ?, ?> tester) {
ranges = new ArrayList<Integer[]>();
List<?> childValues = tester.getChildValues();
if (!childValues.isEmpty()) {
assertTrue(
"The list of child values should contain at least 10 items for proper testing",
childValues.size() >= 10
);
}
}
/**
* {@inheritDoc}
*/
@Override
boolean isMultipleSupported() {
return true;
}
/**
* {@inheritDoc}
*/
@Override
void test(T form, Node node) {
rangeIndex = ranges.size();
ranges.add(new Integer[] { 0, getDefaultChildrenCount() });
super.test(form, node);
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
void testAdding(T form, Node parent) {
ChildListNodeTester<T, Object, Object> tester = (ChildListNodeTester<T, Object, Object>) this.tester;
// Retrieve the values that will be used to create the child nodes
List<Object> values = tester.getChildValues();
Integer[] range = ranges.get(rangeIndex);
// Create each child node
for (int index = range[0]; index < range[1]; index++) {
Object value = values.get(index);
assertNotNull("The child value cannot be null", value);
// Create the child node
Object childForm = tester.addChild(form, value);
currentChildrenCount++;
currentChildListCount++;
assertNotNull(
displayString() + " : The child form should have been created",
childForm
);
// Retrieve the list of child nodes and make sure it matches
// the number of child nodes that have been created so far
List<Node> childrenNode = getChildrenNodes(parent);
assertEquals(
displayString() + " : The child node was not created correctly",
currentChildListCount,
childrenNode.size()
);
// Make sure nothing else was created
assertEquals(
"The child node was not created correctly",
currentChildrenCount,
parent.getChildNodes().getLength()
);
}
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
void testInitialState(T form, Node parent) {
ChildListNodeTester<T, Object, Object> tester = (ChildListNodeTester<T, Object, Object>) this.tester;
assertEquals(
displayString() + " : Incorrect number of children was retrieved",
currentChildListCount,
tester.getChildren(form).size()
);
// Test to make sure the number of child nodes is correctly retrieved
assertEquals(
displayString() + " : The number of children is inconsistent",
currentChildListCount,
tester.getChildrenSize(form)
);
// Make sure nothing changed
assertEquals(
displayString() + " : The number of children is inconsistent",
currentChildrenCount,
parent.getChildNodes().getLength()
);
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
void testReading(T form, Node node) {
ChildListNodeTester<T, Object, Object> tester = (ChildListNodeTester<T, Object, Object>) this.tester;
List<Object> values = tester.getChildValues();
List<Object> childForms = tester.getChildren(form);
assertEquals(
displayString() + " : The number of children is inconsistent",
currentChildListCount,
childForms.size()
);
Integer[] range = ranges.get(rangeIndex);
// Read each child within the range
for (int index = range[0]; index < range[1]; index++) {
// Translate the position to the actual position within the list of children
int translatedPosition = translatePosition(rangeIndex, index);
// Retrieve the child
Object childForm = tester.getChild(form, translatedPosition);
assertNotNull(
displayString() + " : The child form cannot be null",
childForm
);
// Retrieve the child value from the child form
Object childValue = tester.getChildValue(childForm);
Object expectedChildValue = values.get(index);
assertEquals(
displayString() + " : The child value was not retrieved correctly",
expectedChildValue,
childValue
);
// Retrieve the child
childForm = childForms.get(translatedPosition);
assertNotNull(
displayString() + " : The child form cannot be null",
childForm
);
// Retrieve the child value from the child form
childValue = tester.getChildValue(childForm);
assertEquals(
displayString() + " : The child value was not retrieved correctly",
expectedChildValue,
childValue
);
}
// Now test reading each child randomly
Random random = new Random();
List<Integer> positions = new ArrayList<Integer>();
for (int index = range[0]; index < range[1]; index++) {
positions.add(index);
}
while (!positions.isEmpty()) {
// Get a new random position
int position = (positions.size() == 1) ? 0 : random.nextInt(positions.size());
int index = positions.remove(position);
// Translate the position to the actual position within the list of children
int translatedPosition = translatePosition(rangeIndex, index);
// Retrieve the child form
Object childForm = tester.getChild(form, translatedPosition);
assertNotNull(
displayString() + " : The child form cannot be null",
childForm
);
// Retrieve the child value from the child form
Object childValue = tester.getChildValue(childForm);
Object expectedChildValue = values.get(index);
// Now retrieve the translated position within the list of values
assertEquals(
displayString() + " : The child value was not retrieved correctly",
expectedChildValue,
childValue
);
// Retrieve the child
childForm = childForms.get(translatedPosition);
assertNotNull(
displayString() + " : The child form cannot be null",
childForm
);
// Retrieve the child value from the child form
childValue = tester.getChildValue(childForm);
assertEquals(
displayString() + " : The child value was not retrieved correctly",
expectedChildValue,
childValue
);
}
}
private void testReadingAfterRemoval(ChildListNodeTester<T, Object, Object> tester,
T form,
List<Object> childForms,
List<Object> values,
int rangesIndexToSkip,
int offset) {
// Iterate through all the ranges to make sure every single child is correct
for (int rangesIndex = 0; rangesIndex < ranges.size(); rangesIndex++) {
// Skip the range that is being used to delete children
if (rangesIndex == rangesIndexToSkip) {
continue;
}
Integer[] range = ranges.get(rangesIndex);
// Iterate through a single range and check every child is read correctly
for (int rangeIndex = range[0]; rangeIndex < range[1]; rangeIndex++) {
// Translate the position to the actual position within the list of children
// but skip the range that is used to delete children, the offset the number
// of children contained by that range
int translatedPosition = translatePosition(rangesIndex, rangeIndex, rangesIndexToSkip);
// The position is after the index used to delete children, adjust the translated
// position by adding the count of remaining children that have not being deleted yet
if (rangesIndex > rangesIndexToSkip) {
translatedPosition += offset;
}
// Retrieve the child form
Object childForm = tester.getChild(form, translatedPosition);
assertNotNull(
displayString() + " : The child form cannot be null",
childForm
);
// Retrieve the child value from the child form
Object childValue = tester.getChildValue(childForm);
Object expectedChildValue = values.get(rangeIndex);
assertEquals(
displayString() + " : The child value was not retrieved correctly",
expectedChildValue,
childValue
);
// Retrieve the child
childForm = childForms.get(translatedPosition);
assertNotNull(
displayString() + " : The child form cannot be null",
childForm
);
// Retrieve the child value from the child form
childValue = tester.getChildValue(childForm);
assertEquals(
displayString() + " : The child value was not retrieved correctly",
expectedChildValue,
childValue
);
}
}
}
private void testReadingAfterRemoval(ChildListNodeTester<T, Object, Object> tester,
T form,
List<Object> childForms,
List<Object> values,
List<Integer> positions) {
int childIndex = 0;
for (Integer position : positions) {
// Retrieve the child form
Object childForm = tester.getChild(form, childIndex++);
assertNotNull(
displayString() + " : The child form cannot be null",
childForm
);
// Retrieve the child value from the child form
Object childValue = tester.getChildValue(childForm);
Object expectedChildValue = values.get(position);
assertEquals(
displayString() + " : The child value was not retrieved correctly",
expectedChildValue,
childValue
);
}
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
void testRemoving(T form, Node node) {
// Nothing to test
if (ranges.isEmpty()) {
return;
}
ChildListNodeTester<T, Object, Object> tester = (ChildListNodeTester<T, Object, Object>) this.tester;
Random random = new Random();
List<Object> values = tester.getChildValues();
List<Object> readOnlyChildForms = tester.getChildren(form);
// Now remove all the children at random position and
// test reading the remaining between each removal
Integer[] range = ranges.get(rangeIndex);
int rangeCount = ranges.size();
// Cache the positions
List<Integer> positions = new ArrayList<Integer>();
for (int index = range[0]; index < range[1]; index++) {
positions.add(index);
}
List<Integer> readOnlyPositions = new ArrayList<Integer>();
readOnlyPositions.addAll(positions);
while (!positions.isEmpty()) {
// Get a new random position
int position = (positions.size() == 1) ? 0 : random.nextInt(positions.size());
positions.remove(position);
readOnlyPositions.remove(position);
// Translate the position to the actual position within the list of children
// plus the position, which the number of items within the range used to delete
// children before the child being deleted
int translatedPosition = position;
if (rangeIndex > 0) {
int previousRangeIndex = rangeIndex - 1;
int lastRangeIndex = ranges.get(previousRangeIndex)[1];
translatedPosition += translatePosition(previousRangeIndex, lastRangeIndex);
}
// Retrieve the child form
tester.removeChild(form, translatedPosition);
currentChildrenCount--;
currentChildListCount--;
// Adjust the cached positions
for (int positionIndex = position; positionIndex < positions.size(); positionIndex++) {
positions.set(positionIndex, positions.get(positionIndex) - 1);
}
//
// Test 1: Make sure only one node was removed
//
// Test to make sure the parent node has the right amount of children left
assertEquals(
displayString() + " : The number of children is inconsistent",
currentChildListCount,
tester.getChildrenSize(form)
);
assertEquals(
displayString() + " : The number of children is inconsistent",
currentChildrenCount,
node.getChildNodes().getLength()
);
// Retrieve the values that will be used to create the child nodes
List<Object> childForms = tester.getChildren(form);
assertEquals(
displayString() + " : The number of children is inconsistent",
currentChildListCount,
childForms.size()
);
//
// Test 2: Read the other children to make sure the right one was removed
//
// Retrieve the child
if (rangeCount == 1) {
testReadingAfterRemoval(tester, form, readOnlyChildForms, values, readOnlyPositions);
}
else {
testReadingAfterRemoval(tester, form, childForms, values, rangeIndex, positions.size());
}
}
// Completed removing the children from the selected range
ranges.remove(rangeIndex);
}
private int translatePosition(int endRangesIndex, int rangeIndexToAdjust) {
return translatePosition(endRangesIndex, rangeIndexToAdjust, -1);
}
private int translatePosition(final int endRangesIndex,
final int rangeIndexToAdjust,
final int rangesIndexToSkip) {
int translatedPosition = 0;
for (int rangesIndex = 0; rangesIndex <= endRangesIndex; rangesIndex++) {
// Skip the specified range since work is being done with it
if (rangesIndex == rangesIndexToSkip) {
continue;
}
Integer[] range = ranges.get(rangesIndex);
// Quick calculation
if (rangesIndex != endRangesIndex) {
translatedPosition += (range[1] - range[0]);
}
// Adjust the index within the range that ends the translation
else {
translatedPosition += (rangeIndexToAdjust - range[0]);
}
}
return translatedPosition;
}
}
private class ChildNodeRunnerAddingController extends Controller {
/**
* {@inheritDoc}
*/
@Override
void log() {
System.out.println("<" + runner.parentNodeName + "><" + runner.tester.getNodeName() + "> : addition");
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
void test(T form, Node node) {
ChildNodeTesterRunner runner = (ChildNodeTesterRunner) this.runner;
runner.currentChildrenCount = currentChildrenCount;
runner.testInitialState(form, node);
runner.testAdding(form, node);
currentChildrenCount = runner.currentChildrenCount;
}
}
private class ChildNodeRunnerReadingController extends Controller {
/**
* {@inheritDoc}
*/
@Override
void log() {
System.out.println("<" + runner.parentNodeName + "><" + runner.tester.getNodeName() + "> : addition");
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
void test(T form, Node node) {
ChildNodeTesterRunner runner = (ChildNodeTesterRunner) this.runner;
runner.currentChildrenCount = currentChildrenCount;
runner.testInitialState(form, node);
runner.testReading(form, node);
currentChildrenCount = runner.currentChildrenCount;
}
}
private class ChildNodeRunnerRemovingController extends Controller {
/**
* {@inheritDoc}
*/
@Override
void log() {
System.out.println("<" + runner.parentNodeName + "><" + runner.tester.getNodeName() + "> : addition");
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
void test(T form, Node node) {
ChildNodeTesterRunner runner = (ChildNodeTesterRunner) this.runner;
runner.currentChildrenCount = currentChildrenCount;
runner.testInitialState(form, node);
runner.testRemoving(form, node);
currentChildrenCount = runner.currentChildrenCount;
}
}
/**
* This <code>ChildNodeTester</code> tests when a form add or remove a single child node.
*/
public interface ChildNodeTester<T, VALUE extends ExternalForm> extends NodeTester<T, VALUE> {
/**
* Adds the single child node to the node represented by the given form.
*
* @param form The external form being tested
* @return The {@link ExternalForm} of the child node that was added
*/
VALUE addChild(T form);
/**
* Retrieves the {@link ExternalForm} representing the single child node.
*
* @param form The external form being tested
* @return The {@link ExternalForm} representing the child node
*/
VALUE getChild(T form);
/**
* Determines whether the given form has a child node with the specific node name.
*
* @param form The external form being tested
* @return <code>true</code> if the document has the single node as a child node of the node
* for which the given form represents; <code>false</code> if the node does not exist
*/
boolean hasChild(T form);
/**
* Removes the single child node from the node represented by the given form.
*
* @param form The external form being tested
*/
void removeChild(T form);
}
/**
* A <code>ChildNodeTesterRunner</code> tests to make sure the single child node is added and
* removed correctly from its parent node.
*/
private class ChildNodeTesterRunner extends NodeTesterRunner {
/**
*
*/
private boolean hasChild;
/**
* Creates a new <code>ChildNodeTesterRunner</code>.
*
* @param tester This object defines a single child node to test
*/
ChildNodeTesterRunner(ChildNodeTester<T, ?> tester) {
super(tester);
}
private String displayString() {
return "<" + getNodeName() + ">";
}
private Node getChildNode(Node node) {
node = node.getFirstChild();
while (node != null) {
if (getNodeName().equals(node.getNodeName())) {
return node;
}
node = node.getNextSibling();
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
boolean isMultipleSupported() {
return false;
}
/**
* {@inheritDoc}
*/
@Override
void testAdding(T form, Node node) {
// Don't add the child if it's not present
if (hasChild) {
return;
}
ChildNodeTester<T, ? extends ExternalForm> tester = (ChildNodeTester<T, ?>) this.tester;
// Add the child node
ExternalForm childForm = tester.addChild(form);
hasChild = true;
currentChildrenCount++;
assertNotNull(
displayString() + " : The child form should exist",
childForm
);
// Make sure the child node was indeed added
assertEquals(
displayString() + " : The number of children is inconsistent",
currentChildrenCount,
node.getChildNodes().getLength()
);
// Make sure the child node is correctly retrieved
assertTrue(
displayString() + " : The child node should have been found",
tester.hasChild(form)
);
// Make sure the right child node was added and is retrieved by the ExternalForm
assertNotNull(
displayString() + " : The child node should exist",
getChildNode(node)
);
// Make sure nothing changed
assertEquals(
displayString() + " : The child node should exist",
currentChildrenCount,
node.getChildNodes().getLength()
);
}
/**
* {@inheritDoc}
*/
@Override
void testInitialState(T form, Node node) {
ChildNodeTester<T, ?> tester = (ChildNodeTester<T, ?>) this.tester;
// Make sure the child node does not exist
assertEquals(
displayString() + " : The child node should not exist",
hasChild,
tester.hasChild(form)
);
// Make sure nothing changed
assertEquals(
displayString() + " : The child node should not exist",
currentChildrenCount,
node.getChildNodes().getLength()
);
// The child node should not exist
if (hasChild) {
assertNotNull(
displayString() + " : The child node should exist",
getChildNode(node)
);
}
else {
assertNull(
displayString() + " : The child node should not exist",
getChildNode(node)
);
}
// Make sure nothing changed
assertEquals(
displayString() + " : The child node should not exist",
currentChildrenCount,
node.getChildNodes().getLength()
);
}
/**
* {@inheritDoc}
*/
@Override
void testReading(T form, Node node) {
}
/**
* {@inheritDoc}
*/
@Override
void testRemoving(T form, Node node) {
// Nothing to remove
if (!hasChild) {
return;
}
ChildNodeTester<T, ?> tester = (ChildNodeTester<T, ?>) this.tester;
// Make sure the child node exists
assertTrue(
displayString() + " : The child node should exist",
tester.hasChild(form)
);
// Make sure nothing changed with the previous check
assertEquals(
displayString() + " : The child node should exist",
currentChildrenCount,
node.getChildNodes().getLength()
);
// Remove the child node
tester.removeChild(form);
currentChildrenCount--;
hasChild = false;
// Make sure the child node was indeed removed
assertEquals(
displayString() + " : The child node should have been removed",
currentChildrenCount,
node.getChildNodes().getLength()
);
// Make sure the right child node was removed
assertNull(
displayString() + " : The wrong child node was removed",
getChildNode(node)
);
// Test to make sure the child node is not found
assertFalse(
displayString() + " : The child node should not exist",
tester.hasChild(form)
);
}
}
/**
* A <code>Controller</code> wraps a {@link NodeTesterRunner} and executes one of the possible
* tests, which is either add, read or remove the property from the node being manipulated by
* the {@link ExternalForm}.
*/
private abstract class Controller {
/**
* The number of children the node currently has, which is required to make sure the runner
* tests the accuracy of the {@link ExternalForm} when it manipulates the node.
*/
int currentChildrenCount;
/**
*
*/
NodeTesterRunner runner;
/**
* Outputs what is being executed.
*/
abstract void log();
/**
* Executes one of the operations that can be performed on an node.
*
* @param form The {@link ExternalForm} to test
* @param node The node that is manipulated by the given {@link ExternalForm}
*/
abstract void test(T form, Node node);
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return getClass().getSimpleName();
}
}
private class DefaultRootNodeTester implements RootNodeTester<T> {
/**
* The list of testers that used to test every single attribute
* nodes of the one represented by this tester.
*/
private List<AttributeNodeTesterRunner> attributes;
/**
* The builder of the {@link ExternalForm} to test.
*/
private ExternalFormBuilder<T> builder;
/**
* The list of testers that used to test every single child nodes of the one represented by
* this tester.
*/
private List<NodeTesterRunner> children;
/**
* Creates a new <code>DefaultRootNodeTester</code>.
*/
private DefaultRootNodeTester() {
super();
attributes = new ArrayList<AttributeNodeTesterRunner>();
children = new ArrayList<NodeTesterRunner>();
}
/**
* {@inheritDoc}
*/
@Override
public void addAttribute(AttributeNodeTester<T, ?> tester) {
attributes.add(new AttributeNodeTesterRunner(tester));
}
/**
* {@inheritDoc}
*/
@Override
public void addListNodes(ChildListNodeTester<T, ?, ?> tester) {
children.add(new ChildListNodeTesterRunner(tester));
}
/**
* {@inheritDoc}
*/
@Override
public void addNode(ChildNodeTester<T, ?> tester) {
children.add(new ChildNodeTesterRunner(tester));
}
/**
* {@inheritDoc}
*/
@Override
public void addTextNode(TextNodeTester<T, ?> tester) {
children.add(new TextNodeTesterRunner(tester));
}
/**
* {@inheritDoc}
*/
@Override
public void addUnsupportedNode(String nodeName) {
children.add(new NotSupportedNodeTesterRunner(nodeName));
}
@SuppressWarnings({"unchecked", "rawtypes"})
private Map<Class<NodeTesterRunner>, Class<Controller>[]> buildControllerTypes() {
Map classes = new HashMap();
classes.put(
ChildNodeTesterRunner.class,
new Class<?>[] {
ChildNodeRunnerAddingController.class,
ChildNodeRunnerReadingController.class,
ChildNodeRunnerRemovingController.class
}
);
classes.put(
TextNodeTesterRunner.class,
new Class<?>[] {
TextNodeRunnerAddingController.class,
TextNodeRunnerReadingController.class,
TextNodeRunnerRemovingController.class
}
);
classes.put(
ChildListNodeTesterRunner.class,
new Class<?>[] {
ChildListNodeRunnerAddingController.class,
ChildListNodeRunnerReadingController.class,
ChildListNodeRunnerRemovingController.class
}
);
return classes;
}
private String displayString() {
return "<" + builder.getNodeName() + ">";
}
private Node getNode(Node node) {
// The builder is for the root node
if (node.getNodeName().equals(builder.getNodeName())) {
return node;
}
// Dig into the DOM tree to find the child node
return getNode(node, builder.getTreeNodeNames());
}
private Node getNode(Node node, List<String> nodeNames) {
String nodeName = nodeNames.get(0);
node = node.getFirstChild();
while (node != null) {
if (node.getNodeName().equals(nodeName)) {
if (nodeNames.size() == 1) {
return node;
}
return getNode(node, nodeNames.subList(1, nodeName.length()));
}
node = node.getNextSibling();
}
return null;
}
private int getNodePositionOfInsertion(Node node) {
String nodeName = node.getNodeName();
for (int index = 0, count = children.size(); index < count; index++) {
NodeTesterRunner tester = children.get(index);
if (tester.getNodeName().equals(nodeName)) {
return index;
}
}
fail("The child node named <" + nodeName + "> is not included into the test");
return -1;
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
public void setBuilder(ExternalFormBuilder<? extends T> builder) {
this.builder = (ExternalFormBuilder<T>) builder;
}
/**
* Tests the {@link ExternalForm}, which might have attributes and child nodes.
*/
void test() throws Exception {
// Creates the ExternalForm
T form = builder.buildExternalForm();
assertNotNull(
displayString() + " : The external form cannot be null",
form
);
// Retrieve the node represented by the ExternalForm
Node node = builder.getNode(form);
assertNotNull(
displayString() + " : The node cannot be null",
node
);
// Retrieve the node directly from the document
Node expectedNode = getNode(node.getOwnerDocument());
assertSame(
displayString() + " : The node was not retrieved correctly",
expectedNode,
node
);
// Test each attribute
int defaultAttributeCount = builder.getDefaultAttributeCount();
for (AttributeNodeTesterRunner runner : attributes) {
runner.currentChildrenCount = defaultAttributeCount;
runner.parentNodeName = builder.getNodeName();
runner.test(form, node);
assertEquals(
displayString() + " : No number of attributes is inconsistent",
defaultAttributeCount,
node.getAttributes().getLength()
);
}
// Test each child node
for (NodeTesterRunner runner : children) {
runner.parentNodeName = builder.getNodeName();
runner.test(form, node);
assertEquals(
displayString() + " : No child nodes should have been left after a test",
0,
node.getChildNodes().getLength()
);
}
// Now test manipulating the attributes in random order
testAttributesRandomly(form, node);
// Now test manipulating the child nodes in random order
testChildNodesRandomly(form, node);
}
private void testAttributesRandomly(T form, Node node) {
}
private void testChildNodesRandomly(T form, Node parent) throws Exception {
// The list of controllers is used to execute a single test for a particular,
// a list will be generated randomly to test the order
Map<Class<NodeTesterRunner>, Class<Controller>[]> controllerClasses = buildControllerTypes();
List<Controller> controllers = new ArrayList<Controller>();
Random random = new Random();
int childrenCount = children.size();
int controllerTypeCount = controllerClasses.size();
int executionCount = childrenCount * controllerTypeCount * 20;
// Let's run each Runner something like 20 times
for (int index = 0; index < executionCount; index++) {
// Get the runner randomly
int childIndex = random.nextInt(childrenCount);
NodeTesterRunner runner = children.get(childIndex);
// Get the controller type randomly
int controllerIndex = random.nextInt(controllerTypeCount);
Class<Controller>[] controllerTypes = controllerClasses.get(runner.getClass());
// Happen for unsupported node name
if (controllerTypes == null) {
continue;
}
Class<Controller> controllerType = controllerTypes[controllerIndex];
// Create the controller
Controller controller = ClassTools.newInstance(
controllerType,
AbstractExternalFormTests.class,
AbstractExternalFormTests.this
);
controller.runner = runner;
controllers.add(controller);
}
// Run each controller and keep the child nodes count up to date
for (Controller controller : controllers) {
controller.currentChildrenCount = parent.getChildNodes().getLength();
// controller.log();
controller.test(form, parent);
// Retrieve the ordinal of each child node
Node childNode = parent.getFirstChild();
if (childNode != null) {
List<Integer> nodePositions = new ArrayList<Integer>();
do {
int nodePosition = getNodePositionOfInsertion(childNode);
nodePositions.add(nodePosition);
childNode = childNode.getNextSibling();
}
while (childNode != null);
// Make sure the ordinal numbers are from the smaller number to the biggest number
int previousPosition = -1;
for (int nodePosition : nodePositions) {
if (nodePosition < previousPosition) {
fail("The insertion was not performed following the ordering.");
}
}
}
}
}
}
/**
* A <code>ExternalFormBuilder</code> is responsible to create the {@link ExternalForm} to be tested.
*/
public interface ExternalFormBuilder<T extends ExternalForm> {
/**
* Creates the {@link ExternalForm} to test.
*
* @return The {@link ExternalForm} to test
* @throws IOException If an error occurred during the creation process
*/
T buildExternalForm() throws IOException;
/**
* Returns the number of attributes the {@link Node} contains before any manipulation has been performed.
*
* @return The count of children before any testing has been done
*/
int getDefaultAttributeCount();
/**
* Returns the node represented by the {@link ExternalForm}.
*
* @param form The {@link ExternalForm} for which to return its node
* @return The node from the document that is been manipulated
*/
Node getNode(T form);
String getNodeName();
List<String> getTreeNodeNames();
}
private interface NodeTester<T, Value> {
/**
* Retrieves the name of the node for which retrieving and setting its value is tested.
*
* @return The name of the node to test
*/
String getNodeName();
}
private abstract class NodeTesterRunner {
/**
*
*/
int currentChildrenCount;
/**
*
*/
String parentNodeName;
/**
* This object defines a single node to test (which is either a child element or an attribute).
*/
final NodeTester<T, Object> tester;
/**
* Creates a new <code>AbstractNodeTester</code>.
*
* @param tester The bridge between this tester and the document's node being tested
*/
@SuppressWarnings("unchecked")
NodeTesterRunner(NodeTester<T, ?> tester) {
super();
this.tester = (NodeTester<T, Object>) tester;
assertNotNull("The tester cannot be null", tester);
assertNotNull("The node name cannot be null", tester.getNodeName());
}
/**
* Returns the name of the node for which this runner tests.
*
* @return The node name
*/
final String getNodeName() {
return tester.getNodeName();
}
/**
* Determines whether
*
* @return
*/
abstract boolean isMultipleSupported();
/**
* Tests the given {@link ExternalForm} by manipulating the node for a single property.
*
* @param form The {@link ExternalForm} to test
* @param node The node that is manipulated by the given {@link ExternalForm}
*/
void test(T form, Node node) {
testInitialState(form, node);
testAdding(form, node);
testReading(form, node);
testRemoving(form, node);
}
/**
* Tests the given {@link ExternalForm} by adding the property to the node.
*
* @param form The {@link ExternalForm} to test
* @param node The node that is manipulated by the given {@link ExternalForm}
*/
abstract void testAdding(T form, Node node);
/**
* Tests the given {@link ExternalForm} by making sure the given node is in its original state.
*
* @param form The {@link ExternalForm} to test
* @param node The node that is manipulated by the given {@link ExternalForm}
*/
abstract void testInitialState(T form, Node node);
/**
* Tests the given {@link ExternalForm} by reading the property from the node.
*
* @param form The {@link ExternalForm} to test
* @param node The node that is manipulated by the given {@link ExternalForm}
*/
abstract void testReading(T form, Node node);
/**
* Tests the given {@link ExternalForm} by removing the property from the node.
*
* @param form The {@link ExternalForm} to test
* @param node The node that is manipulated by the given {@link ExternalForm}
*/
abstract void testRemoving(T form, Node node);
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return getClass().getSimpleName() + " : " + tester.getNodeName();
}
}
private class NotSupportedNodeTester implements NodeTester<T, Object> {
/**
* The name of the node that is currently not supported by the {@link ExternalForm}.
*/
private String nodeName;
/**
* Creates a new <code>NotSupportedNodeTester</code>.
*
* @param nodeName The name of the node that is currently not supported by the {@link ExternalForm}
*/
NotSupportedNodeTester(String nodeName) {
super();
this.nodeName = nodeName;
}
/**
* {@inheritDoc}
*/
@Override
public String getNodeName() {
return nodeName;
}
}
private class NotSupportedNodeTesterRunner extends NodeTesterRunner {
/**
* Creates a new <code>NotSupportedNodeTesterRunner</code>.
*
* @param nodeName The name of the node that is currently not supported by the {@link ExternalForm}
*/
NotSupportedNodeTesterRunner(String nodeName) {
super(new NotSupportedNodeTester(nodeName));
}
/**
* {@inheritDoc}
*/
@Override
boolean isMultipleSupported() {
return false;
}
/**
* {@inheritDoc}
*/
@Override
void testAdding(T form, Node node) {
// Nothing to do
}
/**
* {@inheritDoc}
*/
@Override
void testInitialState(T form, Node node) {
// Nothing to do
}
/**
* {@inheritDoc}
*/
@Override
void testReading(T form, Node node) {
// Nothing to do
}
/**
* {@inheritDoc}
*/
@Override
void testRemoving(T form, Node node) {
// Nothing to do
}
}
private abstract class PropertyNodeTesterRunner extends NodeTesterRunner {
/**
* Keeps track of the status of the node's existence.
*/
private boolean nodeExists;
/**
* Creates a new <code>PropertyNodeTesterRunner</code>.
*
* @param tester This object defines a single node to test a child text node
*/
PropertyNodeTesterRunner(PropertyTester<T, ?> tester) {
super(tester);
}
/**
* Returns
*
* @return
*/
abstract String displayString();
/**
* Returns the number of children owned by the given parent {@link Node}.
*
* @param parentNode The owner of the child node being tested
* @return The count of children, which could be either attributes or child nodes
*/
abstract int getChildrenCount(Node parentNode);
/**
* Returns
*
* @param parentNode
* @return
*/
abstract Node getNode(Node parentNode);
/**
* Returns
*
* @param node
* @return
*/
abstract String getNodeValue(Node node);
/**
* {@inheritDoc}
*/
@Override
final boolean isMultipleSupported() {
return false;
}
/**
* {@inheritDoc}
*/
@Override
void testAdding(T form, Node parentNode) {
PropertyTester<T, Object> tester = (PropertyTester<T, Object>) this.tester;
// Change the node value to null
if (tester.isNullAllowed()) {
tester.setValue(form, null);
assertEquals(
displayString() + " : The element should not have any children",
0,
getChildrenCount(parentNode) - currentChildrenCount
);
// Make sure nothing changed
Object result = tester.getValue(form);
assertNull(
displayString() + " : The element's value should be null",
result
);
// Make sure nothing changed
assertEquals(
displayString() + " : The element should not have any children",
0,
getChildrenCount(parentNode) - currentChildrenCount
);
}
// Change the value to something
Object expectedValue1 = tester.getValue1();
assertNotNull(
displayString() + " : Value 1 cannot be null",
expectedValue1
);
tester.setValue(form, expectedValue1);
// The child node should have been added
Node childNode = getNode(parentNode);
assertNotNull(
displayString() + " : The node cannot be null",
childNode
);
assertEquals(
displayString() + " : The element should have a " + (nodeExists ? currentChildrenCount : currentChildrenCount + 1) + " children",
nodeExists ? 0 : 1,
getChildrenCount(parentNode) - currentChildrenCount
);
// Get the value
Object result = tester.getValue(form);
assertEquals(
displayString() + "The element's value was not set correctly",
expectedValue1,
result
);
// Get the value directly
String stringResult = getNodeValue(childNode);
String stringNodeValue = tester.toString(expectedValue1);
assertEquals(
displayString() + " : The value was not set correctly",
stringNodeValue,
stringResult
);
// Change the value to something else
Object expectedValue2 = tester.getValue2();
assertNotNull(displayString() + " : Value 2 cannot be null", expectedValue2);
assertNotSame(
displayString() + " : Value 1 and value 2 cannot be the same",
expectedValue1,
expectedValue2
);
tester.setValue(form, expectedValue2);
// Get the value
result = tester.getValue(form);
assertEquals(
displayString() + " The element's value was not set correctly",
expectedValue2,
result
);
// Get the value directly
stringResult = getNodeValue(childNode);
stringNodeValue = tester.toString(expectedValue2);
assertEquals(
displayString() + " : The element's value was not set correctly",
stringNodeValue,
stringResult
);
// Change the value back to its original value
tester.setValue(form, tester.getDefaultValue());
}
/**
* {@inheritDoc}
*/
@Override
void testInitialState(T form, Node parent) {
PropertyTester<T, Object> tester = (PropertyTester<T, Object>) this.tester;
nodeExists |= tester.doesNodeExistAlready();
// Node name
String nodeName = getNodeName();
assertNotNull("The node name cannot be null", nodeName);
// Test the initial state of the parent node
assertEquals(
displayString() + " : The parent node child count is incorrect",
0,
getChildrenCount(parent) - currentChildrenCount
);
// The child node should either not exist or already being present
Node childNode = getNode(parent);
if (nodeExists) {
assertNotNull(
displayString() + " : The node should not be null",
childNode
);
}
else {
assertNull(
displayString() + " : The node should be null",
childNode
);
}
}
/**
* {@inheritDoc}
*/
@Override
void testReading(T form, Node node) {
PropertyTester<T, Object> tester = (PropertyTester<T, Object>) this.tester;
// The node value should either be null or not null
Object result = tester.getValue(form);
// Make sure the node's value is not null
if (nodeExists) {
assertNotNull(
displayString() + " : The element's value should not be null",
result
);
assertSame(
displayString() + " : The element's value was not retrived correctly",
tester.getDefaultValue(),
result
);
}
// The node is not present, make sure reading its value returns null
else {
assertNull(
displayString() + " : The element's value should be null",
result
);
}
// Make sure nothing changed by reading the node's value
assertEquals(
displayString() + " : The element should not have any children",
0,
getChildrenCount(node) - currentChildrenCount
);
// Retrieve the actual node
Node childNode = getNode(node);
if (nodeExists) {
assertNotNull(
displayString() + " : The node should not be null",
childNode
);
}
else {
assertNull(
displayString() + " : The node should be null",
childNode
);
}
// Make sure nothing changed after retrieving the node
assertEquals(
displayString() + " : The element should not have any children",
0,
getChildrenCount(node) - currentChildrenCount
);
}
/**
* {@inheritDoc}
*/
@Override
void testRemoving(T form, Node parentNode) {
PropertyTester<T, Object> tester = (PropertyTester<T, Object>) this.tester;
// Change the node value to null, which will remove it from the parent node
if (tester.isNullAllowed()) {
tester.setValue(form, null);
assertEquals(
displayString() + " : The child count does not match the current state",
0,
getChildrenCount(parentNode) - currentChildrenCount
);
}
}
}
/**
* A <code>PropertyTester</code> handles testing either an attribute or a single child node of
* the node being tested.
*/
private interface PropertyTester<T, VALUE> extends NodeTester<T, VALUE> {
/**
* Determines whether the property is by default present in the document.
*
* @return <code>true</code> if the property exists before any changes is done to the document;
* <code>false</code> otherwise
*/
boolean doesNodeExistAlready();
/**
* If {@link #doesNodeExistAlready()} returns <code>true</code>, then this should return the
* node value that is already present in the document, which is done before the document is
* being changed.
*
* @return Either a non-<code>null</code> value if the node is present in the document or
* <code>null</code> if the node is not by default present in the document
*/
VALUE getDefaultValue();
/**
* Retrieves the value of the node.
*
* @param form The external form that will retrieve the value
* @return The value, which can be <code>null</code>
*/
VALUE getValue(T form);
/**
* Retrieves a non-<code>null</code> value that will be used for testing that is different
* than the one returned by {@link #getValue2()}.
*
* @return A non-<code>null</code> value used for testing
*/
VALUE getValue1();
/**
* Retrieves a non-<code>null</code> value that will be used for testing that is different
* than the one returned by {@link #getValue1()}.
*
* @return A non-<code>null</code> value used for testing
*/
VALUE getValue2();
/**
* Determines whether the node can receive a <code>null</code> value or not.
*
* @return <code>true</code> if <code>null</code> is a valid value; <code>false</code> otherwise
*/
boolean isNullAllowed();
/**
* Sets the value of the node.
*
* @param form The external form that will set the value
* @return The value, which can be <code>null</code>
*/
void setValue(T form, VALUE value);
/**
* Converts the value to its string representation.
*
* @param value A non-<code>null</code> value to convert into a string
* @return The given value represented as a string
*/
String toString(VALUE value);
}
/**
* A <code>RootNodeTester</code> is the container of all the testers that will test every single
* property of the node to test, i.e. its attributes and child nodes.
*/
public interface RootNodeTester<T extends ExternalForm> {
/**
* Adds the given tester when the form has an attribute.
*
* @param tester The tester for a single attribute
*/
void addAttribute(AttributeNodeTester<T, ?> tester);
/**
* Adds the given tester when the form representing the node it represents can have zero or
* many child nodes of the same type (i.e. with the same node name).
*
* @param tester The tester for a list of child nodes with the same type
*/
void addListNodes(ChildListNodeTester<T, ?, ?> tester);
/**
* Adds the given tester when the form representing the node it represents can have one child
* node of a certain type.
*
* @param tester The tester for a single child node
*/
void addNode(ChildNodeTester<T, ?> tester);
/**
* Adds the given tester when the form has a single child node that is a text node.
*
* @param tester The tester for a single child text node
*/
void addTextNode(TextNodeTester<T, ?> tester);
/**
* Adds the given node name to indicate it is part of the "root" node but it is not supported
* by the {@link ExternalForm} yet.
*
* @param nodeName The name of the node not currently supported
*/
void addUnsupportedNode(String nodeName);
/**
* Sets the builder that will create the document and tree node representation down to node to test.
*
* @param builder The builder of the node to test
*/
void setBuilder(ExternalFormBuilder<? extends T> builder);
}
private class TextNodeRunnerAddingController extends Controller {
/**
* {@inheritDoc}
*/
@Override
void log() {
System.out.println("<" + runner.parentNodeName + "><" + runner.tester.getNodeName() + "> : addition");
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
void test(T form, Node node) {
TextNodeTesterRunner runner = (TextNodeTesterRunner) this.runner;
runner.currentChildrenCount = currentChildrenCount;
runner.testInitialState(form, node);
runner.testAdding(form, node);
currentChildrenCount = runner.currentChildrenCount;
}
}
private class TextNodeRunnerReadingController extends Controller {
/**
* {@inheritDoc}
*/
@Override
void log() {
System.out.println("<" + runner.parentNodeName + "><" + runner.tester.getNodeName() + "> addition");
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
void test(T form, Node node) {
TextNodeTesterRunner runner = (TextNodeTesterRunner) this.runner;
runner.currentChildrenCount = currentChildrenCount;
runner.testInitialState(form, node);
runner.testReading(form, node);
currentChildrenCount = runner.currentChildrenCount;
}
}
private class TextNodeRunnerRemovingController extends Controller {
/**
* {@inheritDoc}
*/
@Override
void log() {
System.out.println("<" + runner.parentNodeName + "><" + runner.tester.getNodeName() + "> : addition");
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
void test(T form, Node node) {
TextNodeTesterRunner runner = (TextNodeTesterRunner) this.runner;
runner.currentChildrenCount = currentChildrenCount;
runner.testInitialState(form, node);
runner.testRemoving(form, node);
currentChildrenCount = runner.currentChildrenCount;
}
}
/**
* A <code>TextNodeTester</code> tests setting and retrieving the value associated with a text node.
*/
public interface TextNodeTester<T, VALUE> extends PropertyTester<T, VALUE> {
}
/**
* <p>A <code>TextNodeTesterRunner</code> tests setting and retrieving the value associated with
* a text node.</p>
* <div nowrap>Form: <code><b>&lt;node_name&gt;text&lt;/node_name&gt;</b></code>.</div>
*/
private class TextNodeTesterRunner extends PropertyNodeTesterRunner {
/**
* Creates a new <code>TextNodeTesterRunner</code>.
*
* @param tester This object defines a single node to test a child text node
*/
TextNodeTesterRunner(TextNodeTester<T, ?> tester) {
super(tester);
}
/**
* {@inheritDoc}
*/
@Override
String displayString() {
return "<" + parentNodeName + "><" + getNodeName() + "></>";
}
/**
* {@inheritDoc}
*/
@Override
int getChildrenCount(Node parentNode) {
return parentNode.getChildNodes().getLength();
}
/**
* {@inheritDoc}
*/
@Override
Node getNode(Node node) {
node = node.getFirstChild();
while (node != null) {
if (getNodeName().equals(node.getNodeName())) {
return node;
}
node = node.getNextSibling();
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
String getNodeValue(Node node) {
return node.getTextContent();
}
}
}