/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community 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://opensource.org/licenses/ecl2.txt
*
* 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.opencastproject.util.data;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.opencastproject.util.data.Arrays.array;
import static org.opencastproject.util.data.Collections.iterator;
import static org.opencastproject.util.data.Collections.list;
import static org.opencastproject.util.data.Collections.repeat;
import static org.opencastproject.util.data.Iterators.constant;
import static org.opencastproject.util.data.Iterators.intRangeE;
import static org.opencastproject.util.data.Monadics.IteratorMonadic;
import static org.opencastproject.util.data.Monadics.mlazy;
import static org.opencastproject.util.data.Monadics.mlist;
import static org.opencastproject.util.data.Option.none;
import static org.opencastproject.util.data.Option.some;
import static org.opencastproject.util.data.Tuple.tuple;
import org.opencastproject.util.data.functions.Booleans;
import org.opencastproject.util.data.functions.Functions;
import org.junit.Test;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
public class MonadicsTest {
@Test
public void testMap() {
List<Integer> list = asList(1, 2, 3);
List<String> mapped = mlist(list).map(new Function<Integer, Integer>() {
@Override
public Integer apply(Integer a) {
return a * a;
}
}).map(new Function<Integer, String>() {
@Override
public String apply(Integer a) {
return a + " " + a;
}
}).value();
assertEquals("1 1", mapped.get(0));
assertEquals("4 4", mapped.get(1));
assertEquals("9 9", mapped.get(2));
}
@Test
public void testFlatMap() {
List<Integer> mapped = mlist(new Integer[]{1, 2, 3}).flatMap(new Function<Integer, Collection<Integer>>() {
@Override public Collection<Integer> apply(Integer a) {
return asList(a, a);
}
}).value();
assertEquals(6, mapped.size());
assertEquals(new Integer(1), mapped.get(0));
assertEquals(new Integer(2), mapped.get(2));
assertEquals(new Integer(3), mapped.get(4));
}
@Test
public void testFlatMap2() {
final List<Object> l = list((Object) 1);
final List<String> r1 = mlist(l).bind(new Function<Object, Option<String>>() {
@Override public Option<String> apply(Object o) {
return some("x");
}
}).value();
assertEquals(1, r1.size());
assertEquals("x", r1.get(0));
final List<String> r2 = mlist(l).bind(new Function<Object, Option<String>>() {
@Override public Option<String> apply(Object o) {
return none();
}
}).value();
assertEquals(0, r2.size());
}
@Test
public void testFoldl() {
String fold = mlist(new Integer[]{1, 2, 3}).foldl("", new Function2<String, Integer, String>() {
@Override
public String apply(String s, Integer a) {
return s + a + a;
}
});
assertEquals("112233", fold);
}
@Test
public void testReducel() {
String fold = mlist("a", "b", "c").reducel(new Function2<String, String, String>() {
@Override
public String apply(String a, String b) {
return a + "," + b;
}
});
assertEquals("a,b,c", fold);
}
@Test(expected = RuntimeException.class)
public void testReducelError() {
mlist(new String[]{}).reducel(new Function2<String, String, String>() {
@Override
public String apply(String a, String b) {
return a + "," + b;
}
});
}
@Test
public void testFlatten() {
List<Integer> mapped = mlist(list(list(1, 2), list(3, 4))).flatMap(Functions.<List<Integer>>identity()).value();
assertEquals(4, mapped.size());
List<Integer> mapped2 = mlist(some(1), Option.<Integer>option(null), some(3), Option.<Integer>none()).flatMap(Functions.<Option<Integer>>identity()).value();
assertEquals(2, mapped2.size());
}
@Test
public void testTakeArray() {
assertTrue(mlist(array(1, 2, 3, 4, 5)).take(0).value().isEmpty());
assertEquals(3, mlist(array(1, 2, 3, 4, 5)).take(3).value().size());
assertEquals(5, mlist(array(1, 2, 3, 4, 5)).take(5).value().size());
assertEquals(5, mlist(array(1, 2, 3, 4, 5)).take(10).value().size());
}
@Test
public void testTakeList() {
assertTrue(mlist(asList(1, 2, 3, 4, 5)).take(0).value().isEmpty());
assertEquals(3, mlist(asList(1, 2, 3, 4, 5)).take(3).value().size());
assertEquals(5, mlist(asList(1, 2, 3, 4, 5)).take(5).value().size());
assertEquals(5, mlist(asList(1, 2, 3, 4, 5)).take(10).value().size());
}
@Test
public void testTakeIterator() {
assertTrue(mlist(asList(1, 2, 3, 4, 5).iterator()).take(0).value().isEmpty());
assertEquals(3, mlist(asList(1, 2, 3, 4, 5).iterator()).take(3).value().size());
assertEquals(5, mlist(asList(1, 2, 3, 4, 5).iterator()).take(5).value().size());
assertEquals(5, mlist(asList(1, 2, 3, 4, 5).iterator()).take(10).value().size());
}
@Test
public void testDropArray() {
assertTrue(mlist(array(1, 2, 3, 4, 5)).drop(10).value().isEmpty());
assertEquals(3, mlist(array(1, 2, 3, 4, 5)).drop(2).value().size());
assertEquals(1, mlist(array(1, 2, 3, 4, 5)).drop(4).value().size());
assertEquals(5, mlist(array(1, 2, 3, 4, 5)).drop(0).value().size());
}
@Test
public void testLazyMap() {
final boolean[] applied = {false};
IteratorMonadic<Integer> im = mlazy(asList(1, 2, 3, 4, 5))
.map(new Function<Integer, Integer>() {
@Override
public Integer apply(Integer i) {
applied[0] = true;
return i * i;
}
})
.map(new Function<Integer, Integer>() {
@Override
public Integer apply(Integer i) {
applied[0] = true;
return i + i;
}
});
assertFalse(applied[0]);
im.value();
assertFalse(applied[0]);
List<Integer> eval = im.eval();
assertTrue(applied[0]);
assertArrayEquals(new Integer[]{2, 8, 18, 32, 50}, eval.toArray(new Integer[]{}));
// test empty input
assertTrue(Collections.toList(
mlazy(Collections.<Integer>nil()).map(Functions.<Integer>identity()).value()
).isEmpty());
}
@Test
public void testLazyMapIndex() {
List<Integer> eval = mlazy(asList(1, 2, 3, 4, 5)).mapIndex(new Function2<Integer, Integer, Integer>() {
@Override
public Integer apply(Integer n, Integer i) {
return n + i;
}
}).eval();
assertArrayEquals(new Integer[]{1, 3, 5, 7, 9}, eval.toArray(new Integer[]{}));
}
@Test
public void testLazyFlatMap() {
List<Integer> eval = mlazy(asList(1, 2, 3))
.flatMap(new Function<Integer, Iterator<Integer>>() {
@Override
public Iterator<Integer> apply(Integer integer) {
if (integer >= 2) {
return asList(1, 2, 3).iterator();
} else {
return java.util.Collections.<Integer>emptyList().iterator();
}
}
})
.flatMap(new Function<Integer, Iterator<Integer>>() {
@Override
public Iterator<Integer> apply(Integer integer) {
return asList(integer * integer).iterator();
}
})
.eval();
assertArrayEquals(array(1, 4, 9, 1, 4, 9), Collections.toArray(Integer.class, eval));
}
@Test
public void testLazyFlatMap2() {
List<Integer> eval = mlazy(asList(1, 2, 3))
.flatMap(new Function<Integer, Iterator<Integer>>() {
@Override
public Iterator<Integer> apply(Integer integer) {
if (integer != 2) {
return asList(1, 2, 3).iterator();
} else {
return java.util.Collections.<Integer>emptyList().iterator();
}
}
})
.flatMap(new Function<Integer, Iterator<Integer>>() {
@Override
public Iterator<Integer> apply(Integer integer) {
return asList(integer * integer).iterator();
}
})
.eval();
assertArrayEquals(array(1, 4, 9, 1, 4, 9), Collections.toArray(Integer.class, eval));
}
@Test
public void testLazyFlatMapDoubling() {
List<Integer> eval = mlazy(asList(1, 2, 3, 4, 5)).flatMap(MonadicsTest.<Integer>twice()).eval();
assertArrayEquals(new Integer[]{1, 1, 2, 2, 3, 3, 4, 4, 5, 5}, eval.toArray(new Integer[]{}));
}
@Test
public void testLazyFlatMapKeepSize() {
List<Integer> eval = mlazy(asList(1))
.flatMap(new Function<Integer, Iterator<Integer>>() {
@Override
public Iterator<Integer> apply(Integer integer) {
return Option.<Integer>some(2).iterator();
}
})
.eval();
assertArrayEquals(new Integer[]{2}, eval.toArray(new Integer[0]));
}
@Test
public void testLazyFlatMapTimes() {
List<Integer> eval = mlazy(asList(1, 2, 3, 4)).flatMap(times).eval();
assertArrayEquals(new Integer[]{1, 2, 2, 3, 3, 3, 4, 4, 4, 4}, eval.toArray(new Integer[0]));
}
@Test
public void testLazyFlatMapEmptyInput() {
assertTrue(mlazy(java.util.Collections.<Integer>emptyList()).flatMap(times).eval().isEmpty());
}
@Test
public void testLazyFlatMapEmptyOutput() {
// test empty output
List<Integer> eval = mlazy(asList(1, 2, 3))
.flatMap(new Function<Integer, Iterator<Integer>>() {
@Override
public Iterator<Integer> apply(Integer integer) {
return Option.<Integer>none().iterator();
}
})
.eval();
assertTrue(eval.isEmpty());
}
@Test
public void testLazyFlatMapHasNext() {
Iterator<Integer> ints = mlazy(asList(1, 2)).flatMap(MonadicsTest.<Integer>twice()).value();
// test correctness of hasNext()
assertTrue(ints.hasNext());
assertTrue(ints.hasNext());
assertTrue(ints.hasNext());
assertTrue(ints.hasNext());
assertTrue(ints.hasNext());
}
@Test
public void testLazyFlatMapMultiple() {
List<Integer> eval = mlazy(asList(1, 2))
.flatMap(MonadicsTest.<Integer>twice())
.flatMap(MonadicsTest.<Integer>twice())
.eval();
assertArrayEquals(new Integer[]{1, 1, 1, 1, 2, 2, 2, 2}, eval.toArray(new Integer[]{}));
}
@Test
public void testLazyEachEmpty() {
final boolean[] run = {false};
mlazy(java.util.Collections.emptyList())
.each(new Effect<Object>() {
@Override
public void run(Object o) {
run[0] = true;
}
})
.eval();
assertFalse(run[0]);
}
@Test
public void testLazyEach() {
final int[] sum = {0};
mlazy(asList(1, 2, 3, 4, 5))
.each(new Effect<Integer>() {
@Override
public void run(Integer o) {
sum[0] += o;
}
})
.eval();
assertEquals(15, sum[0]);
}
@Test
public void testLazyEachIndexEmpty() {
final boolean[] run = {false};
mlazy(java.util.Collections.emptyList())
.eachIndex(new Effect2<Object, Integer>() {
@Override
public void run(Object o, Integer i) {
run[0] = true;
}
})
.eval();
assertFalse(run[0]);
}
@Test
public void testLazyEachIndex() {
final int[] sum = {0};
mlazy(asList(1, 2, 3, 4, 5))
.eachIndex(new Effect2<Integer, Integer>() {
@Override
public void run(Integer o, Integer i) {
sum[0] += (o * i);
}
})
.eval();
assertEquals(40, sum[0]);
}
@Test
public void testLazyTake() {
assertTrue(mlazy(asList(1, 2, 3, 4, 5)).take(0).eval().isEmpty());
assertEquals(3, mlazy(asList(1, 2, 3, 4, 5)).take(3).eval().size());
assertEquals(5, mlazy(asList(1, 2, 3, 4, 5)).take(5).eval().size());
assertEquals(5, mlazy(asList(1, 2, 3, 4, 5)).take(10).eval().size());
assertEquals(100, mlazy(constant(10)).take(100).eval().size());
}
@Test
public void testLazyFilter() {
assertEquals(5, mlazy(intRangeE(0, 10)).filter(Booleans.lt(5)).eval().size());
assertEquals(10, mlazy(intRangeE(0, 10)).filter(Booleans.lt(100)).eval().size());
assertEquals(0, mlazy(intRangeE(0, 10)).filter(Booleans.lt(0)).eval().size());
}
@Test
public void testLazyExists() {
assertTrue(mlazy(intRangeE(0, 10)).exists(Booleans.gt(5)));
assertFalse(mlazy(intRangeE(0, 10)).exists(Booleans.gt(9)));
}
@Test
public void testZip() {
{
List<Tuple<String, Integer>> r = mlist(new String[]{"a", "b", "c"}).zip(list(1, 2, 3, 4, 5)).value();
assertEquals(3, r.size());
assertEquals(tuple("b", 2), r.get(1));
}
{
List<Tuple<String, Integer>> r = mlist(new String[]{"a", "b", "c"}).zip(Collections.<Integer>nil()).value();
assertEquals(0, r.size());
}
{
List<Tuple<String, Integer>> r = mlist(list("a", "b", "c")).zip(list(1, 2)).value();
assertEquals(2, r.size());
assertEquals(tuple("b", 2), r.get(1));
}
{
List<Tuple<String, Integer>> r = mlist(list("a", "b", "c").iterator()).zip(list(1, 2)).value();
assertEquals(2, r.size());
assertEquals(tuple("b", 2), r.get(1));
}
{
List<Tuple<String, Integer>> r = mlist(Collections.<String>nil().iterator()).zip(list(1, 2)).value();
assertEquals(0, r.size());
}
}
@Test
public void testConcat() {
// does not compile
// final List<Integer> a = mlist(1, 2, 3).concat(list(4, "5")).value();
final List<Integer> a = mlist(1, 2, 3).concat(list(4, 5)).value();
assertEquals(5, a.size());
assertEquals(4, (Object) a.get(3)); // Object cast because of overloading ambiguity
final List<Object> b = mlist((Object) 1).concat(Collections.<Object>list("x")).value();
assertEquals(2, b.size());
assertEquals(1, b.get(0));
assertEquals("x", b.get(1));
}
private static <A> Function<A, Iterator<A>> twice() {
return new Function<A, Iterator<A>>() {
@Override
public Iterator<A> apply(A a) {
return iterator(a, a);
}
};
}
private static Function<Integer, Iterator<Integer>> times = new Function<Integer, Iterator<Integer>>() {
@Override
public Iterator<Integer> apply(Integer a) {
return repeat(a, a);
}
};
}