Verified Commit a51a31a9 authored by Daniel Mangold's avatar Daniel Mangold
Browse files

Added tests for MyTree and MyParenthesesTreeIterator

parent aa3b0d8b
package h05;
import h05.provider.RandomTreeProvider;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource;
import java.util.Iterator;
import java.util.NoSuchElementException;
import static h05.Utils.TestType.Type.CLASS;
import static h05.Utils.*;
import static java.lang.reflect.Modifier.*;
import static org.junit.jupiter.api.Assertions.*;
@TestType(CLASS)
public class MyParenthesesTreeIteratorTest {
public static Class<?> myParenthesesTreeIteratorClass;
private static final String CLASS_NAME = "h05.MyParenthesesTreeIterator";
@BeforeAll
public static void checkClass() {
if (CLASS_CORRECT.containsKey(MyParenthesesTreeIteratorTest.class))
return;
requireTest(MyTreeTest.class);
myParenthesesTreeIteratorClass = getClassForName(CLASS_NAME);
// is not generic
assertEquals(0, myParenthesesTreeIteratorClass.getTypeParameters().length, CLASS_NAME + " must not be generic");
assertEquals("java.util.Iterator<java.lang.Character>", myParenthesesTreeIteratorClass.getGenericInterfaces()[0].getTypeName(),
CLASS_NAME + " must implement Iterator<Character>");
// is not abstract
assertFalse(isAbstract(myParenthesesTreeIteratorClass.getModifiers()), CLASS_NAME + " must not be abstract");
CLASS_CORRECT.put(MyParenthesesTreeIteratorTest.class, true);
}
@ParameterizedTest
@ArgumentsSource(RandomTreeProvider.class)
public void testNext(String treeString) throws ReflectiveOperationException {
requireTest(MyTreeTest.class.getDeclaredMethod("testIterator"), "()");
Iterator<Character> iterator = MyTreeTest.getIterator(treeString);
for (int i = 0; i < treeString.length(); i++)
assertEquals(treeString.charAt(i), iterator.next(), "Character returned by iterator does not equal expected");
assertThrows(NoSuchElementException.class, iterator::next, "Iterator has more elements than expected");
}
@ParameterizedTest
@ArgumentsSource(RandomTreeProvider.class)
public void testHasNext(String treeString) throws ReflectiveOperationException {
requireTest(MyTreeTest.class.getDeclaredMethod("testIterator"), "()");
requireTest(MyParenthesesTreeIteratorTest.class.getDeclaredMethod("testNext", String.class), "()");
Iterator<Character> iterator = MyTreeTest.getIterator(treeString);
for (int i = 0; i < treeString.length(); i++, iterator.next())
assertTrue(iterator.hasNext(), "Iterator should not have reached end yet");
assertFalse(iterator.hasNext(), "Iterator has more elements than expected");
}
@Test
public void testRemove() throws ReflectiveOperationException {
Iterator<Character> iterator = MyTreeTest.getIterator("");
assertThrows(UnsupportedOperationException.class, iterator::remove);
}
}
package h05;
import h05.Utils.TestType;
import h05.provider.RandomTreeProvider;
import h05.provider.TreeProvider;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource;
import javax.management.BadStringOperationException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
import static h05.Utils.*;
import static h05.Utils.TestType.Type.CLASS;
import static java.lang.reflect.Modifier.*;
import static org.junit.jupiter.api.Assertions.*;
@TestType(CLASS)
public class MyTreeTest {
public static Class<?> myTreeClass;
public static Constructor<?> constructor;
public static Field root, nextNodeID;
public static Method buildRecursively, buildIteratively, iterator, isIsomorphic;
private static final String CLASS_NAME = "h05.MyTree";
@BeforeAll
public static void checkClass() {
if (CLASS_CORRECT.containsKey(MyTreeTest.class))
return;
requireTest(MyTreeNodeTest.class);
myTreeClass = getClassForName(CLASS_NAME);
// is not generic
assertEquals(0, myTreeClass.getTypeParameters().length, CLASS_NAME + " must not be generic");
// implements Iterable<Character>
assertEquals("java.lang.Iterable<java.lang.Character>", myTreeClass.getGenericInterfaces()[0].getTypeName(),
CLASS_NAME + " must implement Iterable<Character>");
// is not abstract
assertFalse(isAbstract(myTreeClass.getModifiers()), CLASS_NAME + " must not be abstract");
// constructors
try {
constructor = myTreeClass.getDeclaredConstructor(Reader.class, boolean.class);
} catch (NoSuchMethodException e) {
fail(CLASS_NAME + " is missing a required constructor", e);
}
assertHasModifiers(constructor, Map.of(PUBLIC, true), "Constructor of " + CLASS_NAME + " must be public");
// fields
try {
root = myTreeClass.getDeclaredField("root");
nextNodeID = myTreeClass.getDeclaredField("nextNodeID");
} catch (NoSuchFieldException e) {
fail(CLASS_NAME + " is missing one or more required fields", e);
}
root.setAccessible(true);
nextNodeID.setAccessible(true);
assertHasModifiers(root, Map.of(PRIVATE, true, STATIC, false, FINAL, false));
assertEquals(MyTreeNodeTest.myTreeNodeClass, root.getType(), "root must be of type MyTreeNode");
assertHasModifiers(nextNodeID, Map.of(PRIVATE, true, STATIC, true, FINAL, false));
assertEquals(long.class, nextNodeID.getType(), "nextNodeID must be of type long");
// methods
try {
buildRecursively = myTreeClass.getDeclaredMethod("buildRecursively", Reader.class);
buildIteratively = myTreeClass.getDeclaredMethod("buildIteratively", Reader.class, Stack.class);
iterator = myTreeClass.getDeclaredMethod("iterator");
isIsomorphic = myTreeClass.getDeclaredMethod("isIsomorphic", myTreeClass);
} catch (NoSuchMethodException e) {
fail(CLASS_NAME + " is missing one or more required methods", e);
}
assertHasModifiers(buildRecursively, Map.of(PRIVATE, true, STATIC, false));
assertEquals(MyTreeNodeTest.myTreeNodeClass, buildRecursively.getReturnType(),
"buildRecursively does not have return type MyTreeNode");
assertTrue(() -> {
boolean hasBadStringOperationException = false, hasIOException = false;
for (Class<?> exception : buildRecursively.getExceptionTypes())
if (exception.equals(BadStringOperationException.class))
hasBadStringOperationException = true;
else if (exception.equals(IOException.class))
hasIOException = true;
return hasBadStringOperationException && hasIOException;
}, "buildRecursively does not throw all required potential exceptions");
assertHasModifiers(buildIteratively, Map.of(PRIVATE, true, STATIC, false));
assertEquals(MyTreeNodeTest.myTreeNodeClass, buildIteratively.getReturnType(),
"buildIteratively does not have return type MyTreeNode");
assertTrue(() -> {
boolean hasBadStringOperationException = false, hasIOException = false;
for (Class<?> exception : buildIteratively.getExceptionTypes())
if (exception.equals(BadStringOperationException.class))
hasBadStringOperationException = true;
else if (exception.equals(IOException.class))
hasIOException = true;
return hasBadStringOperationException && hasIOException;
}, "buildIteratively does not throw all required potential exceptions");
assertHasModifiers(isIsomorphic, Map.of(PUBLIC, true, STATIC, false));
assertEquals(boolean.class, isIsomorphic.getReturnType(), "isIsomorphic does not have return type boolean");
CLASS_CORRECT.put(MyTreeTest.class, true);
}
@ParameterizedTest
@ArgumentsSource(TreeProvider.class)
public void testConstructor(String treeString, Boolean shouldThrowException) throws ReflectiveOperationException, IOException {
boolean buildRecursively = RANDOM.nextBoolean();
StringReader reader = new StringReader(treeString);
if (shouldThrowException) {
assertThrows(BadStringOperationException.class, () -> {
try {
constructor.newInstance(reader, buildRecursively);
} catch (ReflectiveOperationException e) {
throw e.getCause();
}
}, "Constructor did not throw BadStringOperationException, called with second parameter = " + buildRecursively);
} else {
Object instance = constructor.newInstance(reader, buildRecursively);
int i = 0;
while (i < treeString.length() && (treeString.charAt(i) == '(' || treeString.charAt(i) == ')'))
i++;
assertEquals(treeString.substring(0, i), TreeProvider.treeToString(root.get(instance), true),
"Trees do not match, called constructor with second parameter = " + buildRecursively);
for (i = treeString.length() - i - 1; i > 0; i--)
assertEquals(treeString.charAt(treeString.length() - i), (char) reader.read(),
"Reader did not return correct character");
assertEquals(-1, reader.read(), "Reader should not have any characters left");
}
}
@Test
public void testIterator() throws ReflectiveOperationException {
requireTest(MyParenthesesTreeIteratorTest.class);
Object instance = constructor.newInstance(new StringReader(""), RANDOM.nextBoolean());
assertEquals(MyParenthesesTreeIteratorTest.myParenthesesTreeIteratorClass, iterator.invoke(instance).getClass(),
"Returned object does not have type MyParenthesesTreeIterator");
}
@SuppressWarnings("unchecked")
public static Iterator<Character> getIterator(String treeString) throws ReflectiveOperationException {
return (Iterator<Character>) iterator.invoke(constructor.newInstance(new StringReader(treeString), false));
}
@ParameterizedTest
@ArgumentsSource(RandomTreeProvider.class)
public void testIsIsomorphic(String treeString) throws ReflectiveOperationException {
Object instance1 = constructor.newInstance(new StringReader(treeString), false),
instance2 = constructor.newInstance(new StringReader(treeString), false);
assertTrue((Boolean) isIsomorphic.invoke(instance1, instance2), "Trees are isomorphic");
assertTrue((Boolean) isIsomorphic.invoke(instance2, instance1), "Trees are isomorphic");
String nonIsomorphicTreeString = RandomTreeProvider.randomTreeString(3, 2);
Object nonIsomorphicInstance = constructor.newInstance(new StringReader(nonIsomorphicTreeString), false);
assertFalse((Boolean) isIsomorphic.invoke(instance1, nonIsomorphicInstance), "Trees are not isomorphic");
assertFalse((Boolean) isIsomorphic.invoke(nonIsomorphicInstance, instance1), "Trees are not isomorphic");
assertFalse((Boolean) isIsomorphic.invoke(instance2, nonIsomorphicInstance), "Trees are not isomorphic");
assertFalse((Boolean) isIsomorphic.invoke(nonIsomorphicInstance, instance2), "Trees are not isomorphic");
}
}
package h05.provider;
import h05.Utils;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import java.util.stream.Stream;
public class RandomTreeProvider implements ArgumentsProvider {
private static final int MAX_STREAM_SIZE = 5;
private static final int MAX_TREE_DEPTH = 3, MAX_NODES = 10;
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.generate(() -> Arguments.of(randomTreeString(MAX_NODES, MAX_TREE_DEPTH))).limit(MAX_STREAM_SIZE);
}
public static String randomTreeString(int maxNodes, int maxTreeDepth) {
int unclosedParentheses = 0, numberOfNodes = 0;
StringBuilder builder = new StringBuilder();
while (numberOfNodes < maxNodes)
if (Utils.RANDOM.nextBoolean() && unclosedParentheses < maxTreeDepth) {
builder.append('(');
unclosedParentheses++;
numberOfNodes++;
} else {
if (unclosedParentheses > 0) {
builder.append(')');
unclosedParentheses--;
} else {
builder.append('(');
unclosedParentheses++;
numberOfNodes++;
}
}
for (; unclosedParentheses > 0; unclosedParentheses--)
builder.append(')');
return builder.toString();
}
}
package h05.provider;
import h05.ListItemTest;
import h05.MyTreeNodeTest;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import java.util.StringJoiner;
import java.util.stream.Stream;
public class TreeProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of(
Arguments.of("()()", false),
Arguments.of("(())(()())", false),
Arguments.of("", false),
Arguments.of("()\n()", false),
Arguments.of("()\nabc", false),
Arguments.of("\n()", false),
Arguments.of("abc", true),
Arguments.of("(()))", true),
Arguments.of(")()()", true),
Arguments.of("(((()()))", true)
);
}
public static String treeToString(Object root, boolean isRoot) throws ReflectiveOperationException {
StringJoiner joiner = new StringJoiner("");
for (Object p = MyTreeNodeTest.successors.get(root); p != null; p = ListItemTest.next.get(p))
joiner.add(treeToString(ListItemTest.key.get(p), false));
return isRoot ? joiner.toString() : "(" + joiner + ")";
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment