Add a CheckTypeTree for fully spanned check-type-related structures.

This commit is contained in:
asofold 2018-01-16 00:18:17 +01:00
parent 532eef14a2
commit 3e81499fa6
2 changed files with 164 additions and 0 deletions

View File

@ -0,0 +1,109 @@
package fr.neatmonster.nocheatplus.components.data.checktype;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.components.data.checktype.CheckTypeTree.CheckTypeTreeNode;
import fr.neatmonster.nocheatplus.hooks.APIUtils;
/**
* Swift sketch of a tree structure, meant to span all check types, holding
* specific data.
*
* @author asofold
*
*/
public abstract class CheckTypeTree<N extends CheckTypeTreeNode<N>> {
public static interface CheckTypeTreeNodeFactory<N extends CheckTypeTreeNode<N>> {
N newNode(CheckType checkType, N parent);
}
public static class CheckTypeTreeNode<N extends CheckTypeTreeNode<N>> {
private final CheckType checkType;
private final N parent;
private final List<N> children;
/**
* Following the principle of 'creation by explosion', all children are
* created in here directly.
*
* @param checkType
*/
@SuppressWarnings("unchecked")
public CheckTypeTreeNode(final CheckType checkType, final N parent,
final CheckTypeTreeNodeFactory<N> factory) {
this.checkType = checkType;
this.parent = parent;
final Set<CheckType> childrenTypes = APIUtils.getDirectChildren(checkType);
final List<N> children = new ArrayList<N>(childrenTypes.size());
for (CheckType childType : childrenTypes) {
children.add(factory.newNode(childType, (N) this));
}
this.children = children;
}
public CheckType getCheckType() {
return checkType;
}
public N getParent() {
return parent;
}
/**
* An unmodifiable collection.
*
* @return
*/
public List<N> getChildren() {
return children;
}
}
private final N rootNode;
private final Map<CheckType, N> nodeMap = new LinkedHashMap<CheckType, N>();
public CheckTypeTree() {
// Protective glasses on..
class DefaultFactory implements CheckTypeTreeNodeFactory<N> {
@Override
public N newNode(CheckType checkType, N parent) {
return CheckTypeTree.this.newNode(checkType, parent, this);
}
};
// Create explosion.
rootNode = newNode(CheckType.ALL, null, new DefaultFactory());
// Create mapping for explosion.
final List<N> allNodes = new LinkedList<N>();
collectNodes(rootNode, allNodes);
for (final N node : allNodes) {
nodeMap.put(node.getCheckType(), node);
}
}
private void collectNodes(final N node, final List<N> bucket) {
bucket.add(node);
for (final N child : node.getChildren()) {
collectNodes(child, bucket);
}
}
/**
* Internal Factory.
* @return
*/
protected abstract N newNode(CheckType checkType, N parent, CheckTypeTreeNodeFactory<N> factory);
public N getNode(CheckType checkType) {
return nodeMap.get(checkType);
}
}

View File

@ -0,0 +1,55 @@
package fr.neatmonster.nocheatplus.test;
import static org.junit.Assert.fail;
import org.junit.Test;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.components.data.checktype.CheckTypeTree;
import fr.neatmonster.nocheatplus.components.data.checktype.CheckTypeTree.CheckTypeTreeNode;
import fr.neatmonster.nocheatplus.components.data.checktype.CheckTypeTree.CheckTypeTreeNodeFactory;
import fr.neatmonster.nocheatplus.hooks.APIUtils;
public class TestCheckTypeTree {
static class TestNode extends CheckTypeTreeNode<TestNode> {
public TestNode(CheckType checkType, TestNode parent,
CheckTypeTreeNodeFactory<TestNode> factory) {
super(checkType, parent, factory);
}
}
@Test
public void testCreationCompleteness() {
CheckTypeTree<TestNode> tree = new CheckTypeTree<TestNode>() {
@Override
protected TestNode newNode(CheckType checkType, TestNode parent,
CheckTypeTreeNodeFactory<TestNode> factory) {
return new TestNode(checkType, parent, factory);
}
};
for (CheckType checkType : CheckType.values()) {
TestNode node = tree.getNode(checkType);
CheckType rct = node.getCheckType();
if (rct != checkType) {
fail("Bad check type, expext " + checkType + ", got instead: " + rct);
}
if (rct.getParent() != null && node.getParent().getCheckType() != rct.getParent()) {
fail("Wrong type of parent.");
}
if (node.getChildren().size() != APIUtils.getDirectChildren(checkType).size()) {
fail("Wrong size of children.");
}
}
if (tree.getNode(null) != null) {
fail("tree.getNode(null) returns a non null node for CheckType: " + tree.getNode(null).getCheckType());
}
}
}