blob: 07172cc5ef0116a60eafd50995db34c99bc462af [file] [log] [blame]
package org.unicode.cldr.unittest;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import org.unicode.cldr.util.DiscreteComparator;
import org.unicode.cldr.util.DiscreteComparator.Builder;
import org.unicode.cldr.util.DiscreteComparator.CycleException;
import org.unicode.cldr.util.DiscreteComparator.MissingItemException;
import org.unicode.cldr.util.DiscreteComparator.Ordering;
import org.unicode.cldr.util.DtdType;
import org.unicode.cldr.util.ElementAttributeInfo;
import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.impl.Relation;
import com.ibm.icu.impl.Row;
import com.ibm.icu.impl.Row.R2;
/**
* Tests the ordering of DTD elements and attributes within the dtd files.
*/
public class TestComparisonBuilder extends TestFmwk {
public static void main(String[] args) {
new TestComparisonBuilder().run(args);
}
private void verifyOrdering(DiscreteComparator<String> comp,
Set<String> children) {
String last = null;
for (String child : children) {
if (last != null) {
int compare = comp.compare(last, child);
if (compare != -1) {
errln("Elements not ordered:\t" + last + ", " + child
+ "; in " + children);
break;
}
}
last = child;
}
}
private void dtdAttributes() {
// NOTE: This method was originally TestDtdAttributes. It's been
// disabled
// because DTD attributes aren't managed
// by FindDtdOrder, which leads to a lot of ordering cycles being found.
// There's no point in reordering the dtd contents to make this test
// pass
// unless FindDtdOrder also checks attributes.
Builder<String> builder = new Builder<String>(Ordering.NATURAL);
for (DtdType dtd : DtdType.values()) {
Relation<String, String> eaInfo = ElementAttributeInfo.getInstance(
dtd).getElement2Attributes();
for (String element : eaInfo.keySet()) {
Set<String> attributes = eaInfo.getAll(element);
if (attributes.size() == 0)
continue;
// logln(dtd + ": " + element + ": " + attributes);
builder.add(attributes);
}
}
DiscreteComparator<String> comp;
try {
comp = builder.get();
} catch (CycleException e) {
errln(e.getMessage() + ",\t" + builder.getCycle());
throw e;
}
logln("Attribute Ordering:\t" + comp.getOrdering().toString());
for (DtdType dtd : DtdType.values()) {
// check that the ordering is right
Relation<String, String> eaInfo = ElementAttributeInfo.getInstance(
dtd).getElement2Attributes();
for (String element : eaInfo.keySet()) {
Set<String> children = eaInfo.getAll(element);
verifyOrdering(comp, children);
}
}
}
public void TestDtdElements() {
Set<String> specials = new HashSet<String>(Arrays.asList(new String[] {
"EMPTY", "PCDATA", "ANY" }));
Builder<String> builder = new Builder<String>(Ordering.NATURAL);
for (DtdType dtd : DtdType.values()) {
if (dtd.rootType != dtd) {
continue;
}
builder.add(dtd.toString());
Relation<String, String> eaInfo = ElementAttributeInfo.getInstance(
dtd).getElement2Children();
for (String element : eaInfo.keySet()) {
Set<String> children = new LinkedHashSet<String>(
eaInfo.getAll(element));
children.removeAll(specials);
if (children.size() == 0)
continue;
// logln(dtd + ": " + element + ": " + children);
builder.add(children);
}
}
DiscreteComparator<String> comp = builder.get();
logln("Element Ordering: " + comp.getOrdering().toString());
for (DtdType dtd : DtdType.values()) {
if (dtd.rootType != dtd) {
continue;
}
Relation<String, String> eaInfo = ElementAttributeInfo.getInstance(
dtd).getElement2Children();
// check that the ordering is right
for (String element : eaInfo.keySet()) {
Set<String> elements = eaInfo.getAll(element);
Set<String> children = new LinkedHashSet<String>(elements);
children.removeAll(specials);
verifyOrdering(comp, children);
}
// check that all can be ordered
try {
Set<String> items = new TreeSet<String>(comp);
items.addAll(eaInfo.keySet()); // we'll get exception if it
// fails
} catch (Exception e) {
Set<String> missing = new LinkedHashSet<String>(eaInfo.keySet());
missing.removeAll(comp.getOrdering());
errln(dtd + "\t" + e.getClass().getName() + "\t"
+ e.getMessage() + ";\tMissing: " + missing);
}
}
}
public void TestMonkey() {
Random random = new Random(1);
Set<R2<Integer, Integer>> soFar = new HashSet<R2<Integer, Integer>>();
for (int j = 0; j < 100; ++j) {
int itemCount = 50;
int linkCount = 1000;
buildNodes(random, soFar, random.nextInt(itemCount - 1) + 1,
random.nextInt(linkCount));
for (Ordering order : Ordering.values()) {
Builder<Integer> builder = new Builder<Integer>(order);
for (R2<Integer, Integer> pair : soFar) {
builder.add(pair.get0(), pair.get1());
}
logln(builder.toString());
DiscreteComparator<Integer> comp = builder.get();
logln("\t" + comp);
for (R2<Integer, Integer> pair : soFar) {
int value = comp.compare(pair.get0(), pair.get1());
if (value >= 0) {
errln("Failure with " + pair);
}
}
}
}
}
private void buildNodes(Random random, Set<R2<Integer, Integer>> soFar,
int items, int links) {
soFar.clear();
for (int i = 0; i < links; ++i) {
Integer start = random.nextInt(items);
Integer end = random.nextInt(10);
if (start.intValue() <= end.intValue())
continue;
soFar.add(Row.of(start, end));
}
}
public void TestCycle3() {
for (Ordering order : Ordering.values()) {
Builder<String> builder = new Builder<String>(order);
builder.add("c", "a");
builder.add("a", "b");
builder.add("b", "c");
mustHaveException(builder);
}
}
public void TestCycle7() {
for (Ordering order : Ordering.values()) {
Builder<String> builder = new Builder<String>(order);
builder.add("f", "a");
builder.add("a", "b");
builder.add("b", "c");
builder.add("b", "q");
builder.add("c", "d");
builder.add("d", "e");
builder.add("e", "f");
mustHaveException(builder);
}
}
public void TestCycle2() {
for (Ordering order : Ordering.values()) {
Builder<String> builder = new Builder<String>(order);
try {
builder.add("c", "d");
builder.add("d", "e");
builder.add("e", "f");
builder.add("b", "b");
DiscreteComparator<String> comp = builder.get();
} catch (CycleException e) {
logln("Expected cycle and got one at:\t" + e.getMessage()
+ ", " + builder.getCycle());
return;
}
throw new IllegalArgumentException(
"Failed to generate CycleException");
}
}
public void TestFallback() {
for (Ordering order : Ordering.values()) {
DiscreteComparator<String> comp = new Builder<String>(order)
.add("a", "b", "c", "d").add("a", "m", "n").get();
logln("Ordering " + comp.getOrdering());
expectException(comp, "a", "a1");
expectException(comp, "a1", "b");
expectException(comp, "a1", "a2");
}
}
private void expectException(DiscreteComparator<String> comp, String a,
String b) {
try {
comp.compare(a, b);
} catch (MissingItemException e) {
logln("Expected missing item and got one at:\t" + e.getMessage());
return;
}
throw new IllegalArgumentException("Failed to generate CycleException");
}
public void TestFallback2() {
for (Ordering order : Ordering.values()) {
Builder<String> builder = new Builder<String>(order);
builder.setFallbackComparator(new Comparator<String>() {
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
builder.add("a", "b");
builder.add("b", "c");
builder.add("b", "d");
DiscreteComparator<String> comp = builder.get();
int result = comp.compare("a", "a1");
if (result != -1)
errln("a >= a1");
result = comp.compare("b", "a1");
if (result != -1)
errln("a1 >= b");
result = comp.compare("a1", "a2");
if (result != -1)
errln("a1 >= a2");
}
}
private <T> void mustHaveException(Builder<T> builder) {
try {
logln(builder.toString());
DiscreteComparator<T> comp = builder.get();
} catch (CycleException e) {
logln("Expected cycle and got one at:\t" + e.getMessage() + ",\t"
+ builder.getCycle());
return;
}
throw new IllegalArgumentException("Failed to generate CycleException");
}
}