From 7ab21d9e7241b491ed4e380ef040fb12b6467602 Mon Sep 17 00:00:00 2001 From: asofold Date: Mon, 16 Feb 2015 12:59:40 +0100 Subject: [PATCH] Let APIUtils.needsSynchronization include NET, use a HashMap, add tests. --- .../nocheatplus/hooks/APIUtils.java | 56 ++++++++++++++----- .../nocheatplus/TestCheckType.java | 47 ++++++++++++++++ 2 files changed, 88 insertions(+), 15 deletions(-) create mode 100644 NCPCore/src/test/java/fr/neatmonster/nocheatplus/TestCheckType.java diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/APIUtils.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/APIUtils.java index 12104ab4..6cdeb91f 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/APIUtils.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/hooks/APIUtils.java @@ -3,6 +3,7 @@ package fr.neatmonster.nocheatplus.hooks; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; @@ -18,28 +19,47 @@ public class APIUtils { /** Only the children. */ private static final Map childrenMap = new HashMap(); - + /** Check including children, for convenient iteration. */ private static final Map withChildrenMap = new HashMap(); + /** Checks/groups that might be run off the primary thread. */ + private static final Set needSync = new HashSet(); + static { + // Parent/children relations. final Map> map = new HashMap>(); for (final CheckType type : CheckType.values()) map.put(type, new LinkedHashSet()); for (final CheckType type : CheckType.values()){ - if (type != CheckType.ALL) map.get(CheckType.ALL).add(type); + if (type != CheckType.ALL) map.get(CheckType.ALL).add(type); for (final CheckType other : CheckType.values()){ if (isParent(other, type)) map.get(other).add(type); } } for (final CheckType parent : map.keySet()){ - final Set set = map.get(parent); - final CheckType[] a = new CheckType[set.size()]; - childrenMap.put(parent, set.toArray(a)); - final CheckType[] aw = new CheckType[set.size() + 1]; - set.toArray(aw); - aw[set.size()] = parent; - withChildrenMap.put(parent, aw); + final Set set = map.get(parent); + final CheckType[] a = new CheckType[set.size()]; + childrenMap.put(parent, set.toArray(a)); + final CheckType[] aw = new CheckType[set.size() + 1]; + set.toArray(aw); + aw[set.size()] = parent; + withChildrenMap.put(parent, aw); + } + // needSync: Note that tests use the same definitions. + for (final CheckType checkType : new CheckType[]{CheckType.CHAT, CheckType.NET}) { + needSync.add(checkType); + } + boolean added = true; + while (added) { // Just in case. + added = false; + for (final CheckType checkType: CheckType.values()) { + // Fill in needSync. + if (checkType.getParent() != null && !needSync.contains(checkType) && needSync.contains(checkType.getParent())) { + needSync.add(checkType); + added = true; + } + } } } @@ -54,7 +74,7 @@ public class APIUtils { public static final Collection getChildren(final CheckType type) { return Arrays.asList(childrenMap.get(type)); } - + /** * Return an unmodifiable collection of the given check type with children. Always returns a collection, does * contain the check type itself. @@ -78,14 +98,20 @@ public class APIUtils { * @return true, if is parent */ public static final boolean isParent(final CheckType supposedParent, final CheckType supposedChild) { - if (supposedParent == supposedChild) return false; - else if (supposedParent == CheckType.ALL) return true; + if (supposedParent == supposedChild) { + return false; + } + else if (supposedParent == CheckType.ALL) { + return true; + } CheckType parent = supposedChild.getParent(); while (parent != null) - if (parent == supposedParent) + if (parent == supposedParent) { return true; - else + } + else { parent = parent.getParent(); + } return false; } @@ -99,7 +125,7 @@ public class APIUtils { * @return true, if successful */ public static final boolean needsSynchronization(final CheckType type) { - return type == CheckType.CHAT || isParent(CheckType.CHAT, type); + return needSync.contains(type); } } diff --git a/NCPCore/src/test/java/fr/neatmonster/nocheatplus/TestCheckType.java b/NCPCore/src/test/java/fr/neatmonster/nocheatplus/TestCheckType.java new file mode 100644 index 00000000..df73ed24 --- /dev/null +++ b/NCPCore/src/test/java/fr/neatmonster/nocheatplus/TestCheckType.java @@ -0,0 +1,47 @@ +package fr.neatmonster.nocheatplus; + +import static org.junit.Assert.fail; + +import org.junit.Test; + +import fr.neatmonster.nocheatplus.checks.CheckType; +import fr.neatmonster.nocheatplus.hooks.APIUtils; + +public class TestCheckType { + + @Test + public void testIsParent() { + for (CheckType parent : CheckType.values()) { + if (parent != CheckType.ALL && !APIUtils.isParent(CheckType.ALL, parent)) { + fail("Expect ALL to be parent of " + parent + " ."); + } + // Rough simplified check by naming. + String parentName = parent.getName(); + for (final CheckType child : CheckType.values()) { + if (child == parent) { + if (APIUtils.isParent(parent, child)) { + fail("Check can't be parent of itself: " + parent); + } + // Ignore otherwise. + continue; + } + String childName = child.getName(); + if (childName.startsWith(parentName) && childName.charAt(parentName.length()) == '.' && !APIUtils.isParent(parent, child)) { + fail("Expect " + parentName + " to be parent of " + childName + "."); + } + } + } + } + + @Test + public void testNeedsSynchronization() { + for (CheckType parent : new CheckType[]{CheckType.CHAT, CheckType.NET}) { + for (CheckType type : CheckType.values()) { + if ((parent == type || APIUtils.isParent(parent, type)) && !APIUtils.needsSynchronization(type)) { + fail("Expect " + type + " to need synchronization, as it is child of " + parent); + } + } + } + } + +}