blob: 226628c88430b5af62fbc493047dfb214f63ec04 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2017 itemis AG (http://www.itemis.eu) and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.xtext.xbase.tests.lib;
import static com.google.common.collect.Lists.*;
import static com.google.common.collect.Sets.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.eclipse.xtext.xbase.lib.Functions;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.Pair;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure2;
import org.junit.Test;
import com.google.common.collect.ForwardingCollection;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
* @author Sebastian Zarnekow - Initial contribution and API
* @author Karsten Thoms - testMap, testFlatMap
*/
public class IterableExtensionsTest extends BaseIterablesIteratorsTest<Iterable<Integer>> {
@Override
protected Iterable<Integer>[] testData(Integer... elements) {
@SuppressWarnings("unchecked")
Iterable<Integer>[] result = new Iterable[] {
Lists.newArrayList(elements),
Lists.newLinkedList(Lists.newArrayList(elements)),
Sets.newLinkedHashSet(Lists.newArrayList(elements)),
Sets.newTreeSet(Lists.newArrayList(elements))
};
return result;
}
@Override
protected Iterable<Integer>[] nullableTestData(Integer... elements) {
@SuppressWarnings("unchecked")
Iterable<Integer>[] result = new Iterable[] {
Lists.newArrayList(elements),
Lists.newLinkedList(Lists.newArrayList(elements)),
Sets.newLinkedHashSet(Lists.newArrayList(elements)),
// Sets.newTreeSet(Lists.newArrayList(elements)) null is not allowed
};
return result;
}
@Override
protected Iterable<Integer> dummy() {
return Collections.emptyList();
}
@Override
protected boolean is(Iterable<Integer> input, Integer... elements) {
return Iterables.elementsEqual(input, Lists.newArrayList(elements));
}
@Override
protected Iterable<Integer> operator_plus(Iterable<Integer> first, Iterable<Integer> second) {
return IterableExtensions.operator_plus(first, second);
}
@Override
protected Integer findFirst(Iterable<Integer> input, Function1<Integer, Boolean> filter) {
return IterableExtensions.findFirst(input, filter);
}
@Override
protected Integer findLast(Iterable<Integer> input, Function1<Integer, Boolean> filter) {
return IterableExtensions.findLast(input, filter);
}
@Override
protected Integer last(Iterable<Integer> input) {
return IterableExtensions.last(input);
}
@Override
protected Integer head(Iterable<Integer> input) {
return IterableExtensions.head(input);
}
@Override
protected void forEach(Iterable<Integer> input, Procedure2<Integer, Integer> proc) {
IterableExtensions.forEach(input, proc);
}
@Override
protected Iterable<Integer> takeWhile(Iterable<Integer> input, Function1<Integer, Boolean> filter) {
return IterableExtensions.takeWhile(input, filter);
}
@Override
protected Iterable<Integer> dropWhile(Iterable<Integer> input, Function1<Integer, Boolean> filter) {
return IterableExtensions.dropWhile(input, filter);
}
@Override
protected Integer max(Iterable<Integer> input) {
return IterableExtensions.max(input);
}
@Override
protected Integer max(Iterable<Integer> input, Comparator<? super Integer> comparator) {
return IterableExtensions.max(input, comparator);
}
@Override
protected Integer maxBy(Iterable<Integer> input, Function1<? super Integer, String> compareBy) {
return IterableExtensions.maxBy(input, compareBy);
}
@Override
protected Integer min(Iterable<Integer> input) {
return IterableExtensions.min(input);
}
@Override
protected Integer min(Iterable<Integer> input, Comparator<? super Integer> comparator) {
return IterableExtensions.min(input, comparator);
}
@Override
protected Integer minBy(Iterable<Integer> input, Function1<? super Integer, String> compareBy) {
return IterableExtensions.minBy(input, compareBy);
}
@Test public void testJoinWithNull() {
List<String> list = Lists.newArrayList("a", null, "c");
String string = IterableExtensions.join(list, ",");
assertEquals("a,null,c", string);
}
@Test public void testSortBy() throws Exception {
List<? extends CharSequence> list = newArrayList("foo","bar","baz");
List<? extends CharSequence> sorted = IterableExtensions.sortBy(list, new Functions.Function1<CharSequence, String>() {
@Override
public String apply(CharSequence p) {
return p.toString();
}
});
assertNotSame(list, sorted);
assertEquals(sorted, newArrayList("bar","baz","foo"));
}
@Test public void testFilterNull() throws Exception {
Iterator<String> iter = IterableExtensions.filterNull(newArrayList("foo", null, "bar")).iterator();
assertEquals("foo", iter.next());
assertEquals("bar", iter.next());
assertFalse(iter.hasNext());
}
@Test public void testJoinWithBeforeAndAfter() throws Exception {
ArrayList<String> list = newArrayList("foo", "bar");
ArrayList<String> singletonList = newArrayList("foo");
ArrayList<String> emptylist = new ArrayList<String>();
final Functions.Function1<String, String> function = new Functions.Function1<String, String>() {
@Override
public String apply(String p) {
return p;
}
};
assertEquals("<foo,bar>", IterableExtensions.join(list, "<", ",", ">", function));
assertEquals("<foo>", IterableExtensions.join(singletonList, "<", ",", ">", function));
assertEquals("", IterableExtensions.join(emptylist, "<", ",", ">", function));
assertEquals("foo,bar>", IterableExtensions.join(list, null, ",", ">", function));
assertEquals("foo>", IterableExtensions.join(singletonList, null, ",", ">", function));
assertEquals("", IterableExtensions.join(emptylist, null, ",", ">", function));
assertEquals("<foobar>", IterableExtensions.join(list, "<", null, ">", function));
assertEquals("<foo>", IterableExtensions.join(singletonList, "<", null, ">", function));
assertEquals("", IterableExtensions.join(emptylist, "<", null, ">", function));
assertEquals("<foo,bar", IterableExtensions.join(list, "<", ",", null, function));
assertEquals("<foo", IterableExtensions.join(singletonList, "<", ",", null, function));
assertEquals("", IterableExtensions.join(emptylist, "<", ",", null, function));
}
@Test public void testIndexed() {
Iterator<Pair<Integer, String>> result = IterableExtensions.indexed(newArrayList("foo", "bar")).iterator();
assertEquals(new Pair<Integer, String>(0, "foo"), result.next());
assertEquals(new Pair<Integer, String>(1, "bar"), result.next());
assertFalse(result.hasNext());
}
class A {}
interface C {}
class B extends A implements C {}
class D extends A {}
@Test public void testReject() {
List<Integer> nullList = new ArrayList<>();
nullList.add(null);
List<Object> objects = newArrayList(1, 2, null, 4l, "String");
assertEquals(newArrayList(1, 2, null, 4l), newArrayList(IterableExtensions.reject(objects, String.class)));
assertEquals(nullList, newArrayList(IterableExtensions.reject(objects, Object.class)));
List<Integer> integerObjects = newArrayList(1, 2, null, 4);
assertEquals(nullList, newArrayList(IterableExtensions.reject(integerObjects, Integer.class)));
List<A> bObjects = newArrayList(new B(), new B(), new D());
assertEquals(0, IterableExtensions.size(IterableExtensions.reject(bObjects, A.class)));
assertEquals(1, IterableExtensions.size(IterableExtensions.reject(bObjects, B.class)));
assertEquals(1, IterableExtensions.size(IterableExtensions.reject(bObjects, C.class)));
assertEquals(2, IterableExtensions.size(IterableExtensions.reject(bObjects, D.class)));
Function1<Integer, Boolean> function = new Function1<Integer, Boolean>() {
@Override
public Boolean apply(Integer p) {
return p % 2 == 0;
}
};
assertEquals(newArrayList(1,3,5),newArrayList(IterableExtensions.reject(newArrayList(1,2,3,4,5), function)));
Function1<Integer, Boolean> functionNullSafe = new Function1<Integer, Boolean>() {
@Override
public Boolean apply(Integer p) {
return p == null || p % 2 == 0;
}
};
assertEquals(newArrayList(1,5),newArrayList(IterableExtensions.reject(newArrayList(1,2,null,4,5), functionNullSafe)));
try {
newArrayList(IterableExtensions.reject(null, function));
fail("NullPointerException expected");
} catch (NullPointerException e) {
// expected NPE
}
try {
Function1<? super Integer, Boolean> nullFn = null;
newArrayList(IterableExtensions.reject(newArrayList(1,2,3), nullFn));
fail("NullPointerException expected");
} catch (NullPointerException e) {
// expected NPE
}
try {
Class<Integer> nullClass = null;
newArrayList(IterableExtensions.reject(newArrayList(1,2,3), nullClass));
fail("NullPointerException expected");
} catch (NullPointerException e) {
// expected NPE
}
Function1<Integer, Boolean> brokenFunction = new Function1<Integer, Boolean>() {
@Override
public Boolean apply(Integer p) {
return null;
}
};
try {
newArrayList(IterableExtensions.reject(newArrayList(1,2,3), brokenFunction));
fail("NullPointerException expected");
} catch (NullPointerException e) {
// expected NPE
}
}
@Test public void testMap () {
ArrayList<String> list = newArrayList("foo", "bar");
final Functions.Function1<String, String> function = new Functions.Function1<String, String>() {
@Override
public String apply(String p) {
return "Hello "+p;
}
};
assertEquals(newArrayList("Hello foo", "Hello bar"), newArrayList(IterableExtensions.map(list, function)));
// test that the returned iterator supports remove on the underyling list
// therefore we need a function that maps to the same object contained in the list
final Functions.Function1<String, String> functionForRemove = new Functions.Function1<String, String>() {
@Override
public String apply(String p) {
return "foo".equals(p) ? p : "Hello "+p;
}
};
assertTrue(list.contains("foo"));
assertEquals(2, list.size());
assertEquals(newArrayList("foo", "Hello bar"), newArrayList(IterableExtensions.map(list, functionForRemove)));
Iterator<String> iterator = IterableExtensions.map(list, functionForRemove).iterator();
iterator.next();
iterator.remove();
assertTrue(!list.contains("foo"));
assertEquals(1, list.size());
}
@Test public void testFlatMap () {
ArrayList<String> list = newArrayList("foo", "bar");
final Functions.Function1<String, Iterable<String>> function = new Functions.Function1<String, Iterable<String>>() {
@Override
public Iterable<String> apply(String p) {
return newArrayList("Hello", p);
}
};
assertEquals(newArrayList("Hello", "foo", "Hello", "bar"), newArrayList(IterableExtensions.flatMap(list, function)));
}
@Test public void testContains() {
ArrayList<String> list = newArrayList("element1", "element2", "element3", null);
assertTrue(IterableExtensions.contains(list, "element3"));
assertTrue(IterableExtensions.contains(list, new String("element3")));
assertTrue(IterableExtensions.contains(list, null));
assertFalse(IterableExtensions.contains(list, "element4"));
assertFalse(IterableExtensions.contains(list, new String("element4")));
}
private static class TestableCollection<T> extends ForwardingCollection<T> {
private Collection<T> original;
boolean containsWasCalled;
Object containsParameter;
public TestableCollection(Collection<T> original) {
super();
this.original = original;
}
@Override
protected Collection<T> delegate() {
return original;
}
@Override
public boolean contains(Object object) {
containsWasCalled = true;
containsParameter = object;
return super.contains(object);
}
}
@Test public void testContainsOnCollection() {
//GIVEN a collection, declared as an iterable
TestableCollection<String> collection = new TestableCollection<String>(newHashSet("element1", "element2", "element3"));
//WHEN we call the contains method via the IterableExtensions
IterableExtensions.contains(collection, "element1");
//THEN we expect that the collection's native contains method was used
assertTrue("IterableExtensions.contains didn't use the collection's native contains method",
collection.containsWasCalled);
assertEquals("element1", collection.containsParameter);
}
}