GeezerVison is showing github.com — #176: Implemented min, minKey, max and maxKey for tree maps. Added a… · functionaljava/functionaljava@2ac9d52
File treeExpand file treeCollapse file tree Open diff view settings props-core-scalacheck/src props-core/src/test/java/fj/data/properties quickcheck/src/main/java/fj/test
Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: core/src/main/java/fj/data/TreeMap.java +28Lines changed: 28 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -308,6 +308,34 @@ public <W> TreeMap<K, W> map(final F<V, W> f) { | 308 | 308 | return new TreeMap<K, W>(tree.map(TreeMap.<K, Option<W>>ord(o), g)); | 309 | 309 | } | 310 | 310 |
| | 311 | + /** | | 312 | + * Returns the minimum (key, value) pair in the tree if the tree is not empty. | | 313 | + */ | | 314 | + public Option<P2<K, V>> min() { | | 315 | + return tree.min().map(p -> p(p._1(), p._2().some())); | | 316 | + } | | 317 | + | | 318 | + /** | | 319 | + * Returns the minimum key in the tree if the tree is not empty. | | 320 | + */ | | 321 | + public Option<K> minKey() { | | 322 | + return tree.min().map(p -> p._1()); | | 323 | + } | | 324 | + | | 325 | + /** | | 326 | + * Returns the maximum (key, value) pair in the tree if the tree is not empty. | | 327 | + */ | | 328 | + public Option<P2<K, V>> max() { | | 329 | + return tree.max().map(p -> p(p._1(), p._2().some())); | | 330 | + } | | 331 | + | | 332 | + /** | | 333 | + * Returns the maximum key in the tree if the tree is not empty. | | 334 | + */ | | 335 | + public Option<K> maxKey() { | | 336 | + return tree.max().map(p -> p._1()); | | 337 | + } | | 338 | + | 311 | 339 | /** | 312 | 340 | * The expression <code>t1.union(t2)</code> takes the left-biased union of <code>t1</code> | 313 | 341 | * and <code>t2</code>. It prefers <code>t1</code> when duplicate keys are encountered. | |
Collapse file Copy file name to clipboardExpand all lines: core/src/test/java/fj/data/TreeMapTest.java +10Lines changed: 10 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 11 | 11 | import org.junit.Test; | 12 | 12 |
| 13 | 13 | import static fj.P.p; | | 14 | +import static fj.data.Option.none; | 14 | 15 | import static fj.data.Option.some; | 15 | 16 | import static org.hamcrest.CoreMatchers.equalTo; | 16 | 17 | import static org.junit.Assert.assertEquals; | @@ -112,4 +113,13 @@ public void testString() { | 112 | 113 | assertThat(t2.toStream(), equalTo(s)); | 113 | 114 | } | 114 | 115 |
| | 116 | + @Test | | 117 | + public void minKey() { | | 118 | + TreeMap<Integer, Integer> t1 = TreeMap.<Integer, Integer>empty(Ord.intOrd); | | 119 | + assertThat(t1.minKey(), equalTo(none())); | | 120 | + TreeMap<Integer, Integer> t2 = t1.set(1, 2).set(2, 4).set(10, 20).set(5, 10).set(0, 100); | | 121 | + assertThat(t2.minKey(), equalTo(some(0))); | | 122 | + assertThat(t2.delete(0).minKey(), equalTo(some(1))); | | 123 | + } | | 124 | + | 115 | 125 | } |
Collapse file Copy file name to clipboardExpand all lines: props-core-scalacheck/src/main/scala/fj/data/ArbitraryTreeMap.scala -16Lines changed: 0 additions & 16 deletions Collapse file Copy file name to clipboardExpand all lines: props-core-scalacheck/src/test/scala/fj/Tests.scala -1Lines changed: 0 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -13,7 +13,6 @@ object Tests { | 13 | 13 | fj.data.CheckHashMap.properties, | 14 | 14 | fj.data.CheckHashSet.properties, | 15 | 15 | fj.data.CheckSet.properties, | 16 | | - fj.data.CheckTreeMap.properties, | 17 | 16 | fj.control.parallel.CheckStrategy.properties, | 18 | 17 | fj.control.parallel.CheckParModule.properties | 19 | 18 | ).flatten | |
Collapse file Copy file name to clipboardExpand all lines: props-core-scalacheck/src/test/scala/fj/data/CheckTreeMap.scala -21Lines changed: 0 additions & 21 deletions Collapse file Copy file name to clipboard +69Lines changed: 69 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +package fj.data.properties; | | 2 | + | | 3 | +import fj.Equal; | | 4 | +import fj.data.TreeMap; | | 5 | +import fj.test.Arbitrary; | | 6 | +import fj.test.Gen; | | 7 | +import fj.test.Property; | | 8 | +import fj.test.reflect.CheckParams; | | 9 | +import fj.test.runner.PropertyTestRunner; | | 10 | +import org.junit.runner.RunWith; | | 11 | + | | 12 | +import java.util.concurrent.atomic.AtomicInteger; | | 13 | + | | 14 | +import static fj.Equal.stringEqual; | | 15 | +import static fj.Ord.intOrd; | | 16 | +import static fj.test.Arbitrary.arbInteger; | | 17 | +import static fj.test.Arbitrary.arbString; | | 18 | +import static fj.test.Arbitrary.arbTreeMap; | | 19 | +import static fj.test.Property.*; | | 20 | + | | 21 | +/** | | 22 | + * Created by MarkPerry on 29/08/2015. | | 23 | + */ | | 24 | +@RunWith(PropertyTestRunner.class) | | 25 | +@CheckParams(maxSize = 10000) | | 26 | +public class TreeMapProperties { | | 27 | + | | 28 | + private static final int smallMax = 5; | | 29 | + private static final int midMax = 20; | | 30 | + public static final Arbitrary<TreeMap<Integer, String>> smallArbTreeMapIS = arbTreeMap(intOrd, arbInteger, arbString, smallMax); | | 31 | + public static final Arbitrary<TreeMap<Integer, String>> arbTreeMapIS = arbTreeMap(intOrd, arbInteger, arbString, midMax); | | 32 | + | | 33 | + public Property empty() { | | 34 | + return property(smallArbTreeMapIS, tm -> impliesBoolean(tm.isEmpty(), tm.size() == 0)); | | 35 | + } | | 36 | + | | 37 | + public Property set() { | | 38 | + return property(arbTreeMapIS, arbInteger, arbString, (tm, k, v) -> | | 39 | + prop(stringEqual.eq(tm.set(k, v).get(k).some(), v)) | | 40 | + ); | | 41 | + } | | 42 | + | | 43 | + public Property updateId() { | | 44 | + return property(arbTreeMapIS, arbInteger, arbString, (tm, k, v) -> | | 45 | + prop(stringEqual.eq(tm.set(k, v).update(k, x -> x)._2().get(k).some(), v)) | | 46 | + ); | | 47 | + } | | 48 | + | | 49 | + public Property update() { | | 50 | + return property(arbTreeMapIS, arbInteger, arbString, arbString, (tm, k, v, v2) -> | | 51 | + prop(stringEqual.eq(tm.set(k, v).update(k, x -> x + v2)._2().get(k).some(), v + v2)) | | 52 | + ); | | 53 | + } | | 54 | + | | 55 | + public Property minKey() { | | 56 | + return property(arbTreeMapIS, tm -> | | 57 | + impliesBoolean(!tm.isEmpty(), () -> Equal.intEqual.eq(tm.minKey().some(), tm.toStream().head()._1())) | | 58 | + ); | | 59 | + } | | 60 | + | | 61 | + public Property maxKey() { | | 62 | + return property(arbTreeMapIS, tm -> | | 63 | + impliesBoolean(!tm.isEmpty(), | | 64 | + () -> Equal.intEqual.eq(tm.maxKey().some(), tm.toStream().reverse().head()._1()) | | 65 | + ) | | 66 | + ); | | 67 | + } | | 68 | + | | 69 | +} |
Collapse file Copy file name to clipboardExpand all lines: quickcheck/src/main/java/fj/test/Arbitrary.java +44-5Lines changed: 44 additions & 5 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 9 | 9 | import fj.F7; | 10 | 10 | import fj.F8; | 11 | 11 | import fj.Function; | | 12 | +import fj.Bottom; | | 13 | + | 12 | 14 | import static fj.Function.compose; | 13 | 15 | import static fj.P.p; | 14 | 16 | import fj.P1; | @@ -1115,22 +1117,59 @@ public Stack<A> f(final Array<A> a) { | 1115 | 1117 | } | 1116 | 1118 |
| 1117 | 1119 | /** | 1118 | | - * Returns an arbitrary implementation for tree maps. | | 1120 | + * Returns an arbitrary implementation for java.util tree maps. | 1119 | 1121 | * | 1120 | 1122 | * @param ak An arbitrary implementation for the type over which the tree map's keys are defined. | 1121 | 1123 | * @param av An arbitrary implementation for the type over which the tree map's values are | 1122 | 1124 | * defined. | 1123 | 1125 | * @return An arbitrary implementation for tree maps. | 1124 | 1126 | */ | 1125 | | - public static <K, V> Arbitrary<TreeMap<K, V>> arbTreeMap(final Arbitrary<K> ak, final Arbitrary<V> av) { | 1126 | | - return arbitrary(arbHashtable(ak, av).gen.map(new F<Hashtable<K, V>, TreeMap<K, V>>() { | | 1127 | + public static <K, V> Arbitrary<java.util.TreeMap<K, V>> arbJavaTreeMap(final Arbitrary<K> ak, final Arbitrary<V> av) { | | 1128 | + return arbitrary(arbHashtable(ak, av).gen.map(new F<Hashtable<K, V>, java.util.TreeMap<K, V>>() { | 1127 | 1129 | @SuppressWarnings({"UseOfObsoleteCollectionType"}) | 1128 | | - public TreeMap<K, V> f(final Hashtable<K, V> ht) { | 1129 | | - return new TreeMap<K, V>(ht); | | 1130 | + public java.util.TreeMap<K, V> f(final Hashtable<K, V> ht) { | | 1131 | + return new java.util.TreeMap<K, V>(ht); | 1130 | 1132 | } | 1131 | 1133 | })); | 1132 | 1134 | } | 1133 | 1135 |
| | 1136 | + /** | | 1137 | + * Returns an arbitrary implementation for tree maps. | | 1138 | + */ | | 1139 | + public static <K, V> Arbitrary<fj.data.TreeMap<K, V>> arbTreeMap(Ord<K> ord, Arbitrary<List<P2<K, V>>> al) { | | 1140 | + return arbitrary(al.gen.map(list -> fj.data.TreeMap.treeMap(ord, list))); | | 1141 | + } | | 1142 | + | | 1143 | + /** | | 1144 | + * Returns an arbitrary implementation for tree maps. | | 1145 | + */ | | 1146 | + public static <K, V> Arbitrary<fj.data.TreeMap<K, V>> arbTreeMap(Ord<K> ord, Arbitrary<K> ak, Arbitrary<V> av) { | | 1147 | + return arbTreeMap(ord, arbList(arbP2(ak, av))); | | 1148 | + } | | 1149 | + | | 1150 | + /** | | 1151 | + * Returns an arbitrary implementation for tree maps where the map size is the given arbitrary integer. | | 1152 | + */ | | 1153 | + public static <K, V> Arbitrary<fj.data.TreeMap<K, V>> arbTreeMap(Ord<K> ord, Arbitrary<K> ak, Arbitrary<V> av, Arbitrary<Integer> ai) { | | 1154 | + Gen<List<P2<K, V>>> gl2 = ai.gen.bind(i -> { | | 1155 | + if (i < 0) { | | 1156 | + Bottom.error("Undefined: arbitrary natural is negative (" + i + ")"); | | 1157 | + } | | 1158 | + return Gen.sequenceN(Math.max(i, 0), Arbitrary.arbP2(ak, av).gen); | | 1159 | + }); | | 1160 | + return arbTreeMap(ord, arbitrary(gl2)); | | 1161 | + } | | 1162 | + | | 1163 | + /** | | 1164 | + * Returns an arbitrary implementation for tree maps where the size is less than or equal to the max size. | | 1165 | + */ | | 1166 | + public static <K, V> Arbitrary<fj.data.TreeMap<K, V>> arbTreeMap(Ord<K> ord, Arbitrary<K> ak, Arbitrary<V> av, int maxSize) { | | 1167 | + if (maxSize < 0) { | | 1168 | + Bottom.error("Undefined: arbitrary natural is negative (" + maxSize + ")"); | | 1169 | + } | | 1170 | + return arbTreeMap(ord, ak, av, arbitrary(Gen.choose(0, maxSize))); | | 1171 | + } | | 1172 | + | 1134 | 1173 | /** | 1135 | 1174 | * Returns an arbitrary implementation for tree sets. | 1136 | 1175 | * | |
Collapse file Copy file name to clipboardExpand all lines: quickcheck/src/main/java/fj/test/Property.java +16Lines changed: 16 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -362,6 +362,22 @@ public Result f(final Rand r) { | 362 | 362 | }); | 363 | 363 | } | 364 | 364 |
| | 365 | + /** | | 366 | + * Returns a property that produces a result only if the given condition satisfies. The result | | 367 | + * will be taken from the given boolean b. | | 368 | + */ | | 369 | + public static Property impliesBoolean(final boolean a, final boolean b) { | | 370 | + return implies(a, () -> Property.prop(b)); | | 371 | + } | | 372 | + | | 373 | + /** | | 374 | + * Returns a property that produces a result only if the given condition satisfies. The result | | 375 | + * will be taken from the given lazy boolean b. | | 376 | + */ | | 377 | + public static Property impliesBoolean(final boolean a, final F0<Boolean> b) { | | 378 | + return implies(a, () -> Property.prop(b.f())); | | 379 | + } | | 380 | + | 365 | 381 | /** | 366 | 382 | * Returns a property from the given function. | 367 | 383 | * | |
Collapse file Copy file name to clipboardExpand all lines: quickcheck/src/main/java/fj/test/runner/PropertyTestRunner.java +6-1Lines changed: 6 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -43,7 +43,8 @@ public void run(RunNotifier notifier) { | 43 | 43 | CheckResult result = checkProperty(p._1(), p._2()); | 44 | 44 |
| 45 | 45 | try { | 46 | | - CheckResult.summaryEx.showS(result); | | 46 | + String s = CheckResult.summaryEx.showS(result); | | 47 | + System.out.println(getLabel(desc) + ": " + s); | 47 | 48 | } catch (Throwable t) { | 48 | 49 | notifier.fireTestFailure(new Failure(desc, t)); | 49 | 50 | } | @@ -52,6 +53,10 @@ public void run(RunNotifier notifier) { | 52 | 53 | }); | 53 | 54 | } | 54 | 55 |
| | 56 | + private static String getLabel(Description d) { | | 57 | + return d.getDisplayName(); | | 58 | + } | | 59 | + | 55 | 60 | private static CheckResult checkProperty(Property prop, Option<CheckParams> params) { | 56 | 61 | for (CheckParams ps : params) { | 57 | 62 | return prop.check(ps.minSuccessful(), ps.maxDiscarded(), ps.minSize(), ps.maxSize()); | |
|