/**
* 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 org.apache.avro.xml;
import static org.junit.Assert.*;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import org.apache.avro.Schema;
import org.custommonkey.xmlunit.DetailedDiff;
import org.custommonkey.xmlunit.XMLUnit;
import org.w3c.dom.Document;
/**
* Utilities to:
*
* <ul>
* <li>Compare two {@link Document}s for equivalence.</li>
* <li>Compare two Avro {@link Schema}s for equivalence</li>
* <li>Build a file path in a cross-platform way.</li>
* </ul>
*/
final class UtilsForTests {
static void assertEquivalent(Document expected, Document actual) {
XMLUnit.setIgnoreWhitespace(true);
XMLUnit.setIgnoreAttributeOrder(true);
DetailedDiff diff = new DetailedDiff(XMLUnit.compareXML(expected, actual));
assertTrue(
"Differences found: " + diff.toString(),
diff.similar());
}
static void assertEquivalent(Schema expected, Schema actual) {
assertEquivalent(expected, actual, new HashSet<String>());
}
private static void assertEquivalent(
Schema expected,
Schema actual,
HashSet<String> recordsSeen) {
assertEquals(expected.getFullName() + " vs. " + actual.getFullName(),
expected.getType(),
actual.getType());
switch ( expected.getType() ) {
case ARRAY:
assertEquivalent(
expected.getElementType(),
actual.getElementType(),
recordsSeen);
break;
case MAP:
assertEquivalent(
expected.getValueType(),
actual.getValueType(),
recordsSeen);
break;
case UNION:
{
List<Schema> expSchemas = expected.getTypes();
HashMap<String, Schema> expFullNames = new HashMap<String, Schema>();
for (Schema expSchema : expSchemas) {
expFullNames.put(expSchema.getFullName(), expSchema);
}
for (Schema actualSchema : actual.getTypes()) {
assertTrue(
"Cannot find field "
+ actualSchema.getFullName()
+ " in "
+ expected.getFullName(),
expFullNames.containsKey( actualSchema.getFullName() ) );
Schema expSchema = expFullNames.remove( actualSchema.getFullName() );
assertEquivalent(expSchema, actualSchema, recordsSeen);
}
assertTrue( expFullNames.isEmpty() );
break;
}
case FIXED:
{
assertEquals(expected.getFullName(), actual.getFullName());
assertEquals(expected.getFixedSize(), actual.getFixedSize());
break;
}
case ENUM:
{
assertEquals(expected.getFullName(), actual.getFullName());
final int numActualSymbols = actual.getEnumSymbols().size();
final List<String> expectedSymbols = expected.getEnumSymbols();
assertEquals(expectedSymbols.size(), numActualSymbols);
for (String expSym : expectedSymbols) {
try {
actual.getEnumOrdinal(expSym);
} catch (Exception e) {
fail("Expected Symbol \""
+ expSym
+ "\" in enum "
+ expected.getFullName()
+ " has no equivalent in actual.");
}
}
break;
}
case RECORD:
{
assertEquals(expected.getFullName(), actual.getFullName());
// Prevents infinite recursive descent.
if ( !recordsSeen.contains( expected.getFullName() ) ) {
recordsSeen.add( expected.getFullName() );
List<Schema.Field> expFields = expected.getFields();
if (expFields.size() != actual.getFields().size()) {
HashSet<String> expectedFields = new HashSet<String>();
for (Schema.Field expField : expFields) {
expectedFields.add(expField.name());
}
HashSet<String> actualFields = new HashSet<String>();
for (Schema.Field actualField : actual.getFields()) {
actualFields.add(actualField.name());
}
List<String> foundExpectedFields = new ArrayList<String>();
for (String expField : expectedFields) {
if (actualFields.contains(expField)) {
foundExpectedFields.add(expField);
actualFields.remove(expField);
}
}
for (String foundExpectedField : foundExpectedFields) {
expectedFields.remove(foundExpectedField);
}
System.err.println("Missing Expected Fields:");
for (String expField : expectedFields) {
System.err.println('\t' + expField);
}
System.err.println("Unexpected Actual Fields:");
for (String actField : actualFields) {
System.err.println('\t' + actField);
}
}
assertEquals(
expected.getFullName(),
expFields.size(),
actual.getFields().size());
for (Schema.Field expField : expFields) {
Schema.Field actualField = actual.getField( expField.name() );
assertNotNull(expected.getFullName() + " field " + expField.name(),
actualField);
assertEquals(expected.getFullName() + " field " + expField.name(),
expField.doc(),
actualField.doc());
assertEquals(expected.getFullName() + " field " + expField.name(),
expField.order(),
actualField.order());
assertEquals(expected.getFullName() + " field " + expField.name(),
expField.defaultValue(),
actualField.defaultValue());
assertEquivalent(expField.schema(),
actualField.schema(),
recordsSeen);
}
}
break;
}
default:
// All primitive types are equal if their types are.
}
}
static File buildFile(String... parts) {
File file = null;
for (String part : parts) {
if (file == null) {
file = new File(part);
} else {
file = new File(file, part);
}
}
return file;
}
}