Fix an issue with the service sub and duplicates

1) The service sub did not remove all the occurrences of an element in a
sequence, only the first occurrence.
2) Improve the documentation

Change-Id: I840b7718cac2e2784cbdda141b37802b14192481
Signed-off-by: sbegaudeau <stephane.begaudeau@obeo.fr>
diff --git a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/services/CollectionServices.java b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/services/CollectionServices.java
index 94fcba9..3134631 100644
--- a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/services/CollectionServices.java
+++ b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/services/CollectionServices.java
@@ -827,10 +827,10 @@
 
 	// @formatter:off
 	@Documentation(
-		value = "Returns the concatenation of the two specified sequences.",
+		value = "Returns the concatenation of the current sequence with the given collection.",
 		params = {
-			@Param(name = "sequence1", value = "The first operand"),
-			@Param(name = "sequence2", value = "The second operand")
+			@Param(name = "sequence", value = "The first operand"),
+			@Param(name = "collection", value = "The second operand")
 		},
 		result = "The concatenation of the two specified sequences.",
 		examples = {
@@ -847,16 +847,16 @@
 		}
 	)
 	// @formatter:on
-	public List<Object> concat(List<Object> sequence1, Collection<Object> sequence2) {
+	public List<Object> concat(List<Object> sequence, Collection<Object> collection) {
 		final List<Object> result;
 
-		if (sequence1.isEmpty()) {
-			result = Lists.newArrayList(sequence2);
-		} else if (sequence2.isEmpty()) {
-			result = sequence1;
+		if (sequence.isEmpty()) {
+			result = Lists.newArrayList(collection);
+		} else if (collection.isEmpty()) {
+			result = sequence;
 		} else {
-			result = Lists.newArrayList(sequence1);
-			result.addAll(sequence2);
+			result = Lists.newArrayList(sequence);
+			result.addAll(collection);
 		}
 
 		return result;
@@ -866,8 +866,8 @@
 	@Documentation(
 		value = "Returns the concatenation of the given collection into the given sequence.",
 		params = {
-			@Param(name = "sequence1", value = "The first operand"),
-			@Param(name = "collection2", value = "The second operand")
+			@Param(name = "sequence", value = "The first operand"),
+			@Param(name = "collection", value = "The second operand")
 		},
 		result = "The current sequence including the elements of the given collection.",
 		examples = {
@@ -895,16 +895,16 @@
 		comment = "The service addAll has been replaced by \"add\" in order to have access to the operator \"+\" between to sequences"
 	)
 	// @formatter:on
-	public List<Object> add(List<Object> sequence1, Collection<Object> collection2) {
-		return concat(sequence1, collection2);
+	public List<Object> add(List<Object> sequence, Collection<Object> collection) {
+		return concat(sequence, collection);
 	}
 
 	// @formatter:off
 	@Documentation(
 		value = "Returns the difference of the current sequence and the given collection.",
 		params = {
-			@Param(name = "sequence1", value = "The first operand"),
-			@Param(name = "collection2", value = "The second operand")
+			@Param(name = "sequence", value = "The first operand"),
+			@Param(name = "collection", value = "The second operand")
 		},
 		result = "The sequence that contains elements from sequence1 that are not in collection2.",
 		examples = {
@@ -932,14 +932,12 @@
 		comment = "The service removeAll has been replaced by \"sub\" in order to have access to the operator \"-\" between to sequences"
 	)
 	// @formatter:on
-	public List<Object> sub(List<Object> sequence1, Collection<Object> collection2) {
-		if (collection2.isEmpty()) {
-			return sequence1;
+	public List<Object> sub(List<Object> sequence, Collection<Object> collection) {
+		if (collection.isEmpty()) {
+			return sequence;
 		} else {
-			List<Object> result = Lists.newArrayList(sequence1);
-			for (Object obj : collection2) {
-				result.remove(obj);
-			}
+			List<Object> result = Lists.newArrayList(sequence);
+			result.removeAll(collection);
 			return result;
 		}
 	}
@@ -948,8 +946,8 @@
 	@Documentation(
 		value = "Returns the difference of the current set and the given collection.",
 		params = {
-			@Param(name = "set1", value = "The first operand"),
-			@Param(name = "collection2", value = "The second operand")
+			@Param(name = "set", value = "The first operand"),
+			@Param(name = "collection", value = "The second operand")
 		},
 		result = "The set that contains elements from set1 that are not in collection2.",
 		examples = {
@@ -967,14 +965,12 @@
 		comment = "The service removeAll has been replaced by \"sub\" in order to have access to the operator \"-\" between to sets"
 	)
 	// @formatter:on
-	public Set<Object> sub(Set<Object> set1, Collection<Object> collection2) {
-		if (collection2.isEmpty()) {
-			return set1;
+	public Set<Object> sub(Set<Object> set, Collection<Object> collection) {
+		if (collection.isEmpty()) {
+			return set;
 		} else {
-			Set<Object> result = Sets.newLinkedHashSet(set1);
-			for (Object obj : collection2) {
-				result.remove(obj);
-			}
+			Set<Object> result = Sets.newLinkedHashSet(set);
+			result.removeAll(collection);
 			return result;
 		}
 	}
diff --git a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/CollectionServicesTest.java b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/CollectionServicesTest.java
index ef744c6..2355601 100644
--- a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/CollectionServicesTest.java
+++ b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/CollectionServicesTest.java
@@ -53,8 +53,8 @@
 import org.eclipse.acceleo.query.tests.anydsl.World;
 import org.eclipse.emf.common.notify.Notifier;
 import org.eclipse.emf.common.util.TreeIterator;
-import org.eclipse.emf.ecore.EClassifier;
 import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
 import org.eclipse.emf.ecore.ENamedElement;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.EPackage;
@@ -187,6 +187,48 @@
 	}
 
 	@Test
+	public void testConcatWithDuplicates() {
+		List<Object> list1 = Lists.newArrayList();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		list1.add("c");
+		list1.add("c");
+
+		List<Object> list2 = Lists.newArrayList();
+		list2.add("c");
+		list2.add("b");
+		list2.add("a");
+
+		List<Object> result = collectionServices.concat(list1, list2);
+		assertEquals(8, result.size());
+		assertEquals("a", result.get(0));
+		assertEquals("b", result.get(1));
+		assertEquals("c", result.get(2));
+		assertEquals("c", result.get(3));
+		assertEquals("c", result.get(4));
+		assertEquals("c", result.get(5));
+		assertEquals("b", result.get(6));
+		assertEquals("a", result.get(7));
+
+		Set<Object> set1 = Sets.newLinkedHashSet();
+		set1.add("c");
+		set1.add("b");
+		set1.add("a");
+
+		List<Object> result2 = collectionServices.concat(list1, set1);
+		assertEquals(8, result2.size());
+		assertEquals("a", result2.get(0));
+		assertEquals("b", result2.get(1));
+		assertEquals("c", result2.get(2));
+		assertEquals("c", result2.get(3));
+		assertEquals("c", result2.get(4));
+		assertEquals("c", result2.get(5));
+		assertEquals("b", result2.get(6));
+		assertEquals("a", result2.get(7));
+	}
+
+	@Test
 	public void testAddList() {
 		List<Object> list1 = Lists.newArrayList();
 		List<Object> list2 = Lists.newArrayList();
@@ -230,6 +272,48 @@
 	}
 
 	@Test
+	public void testAddListWithDuplicates() {
+		List<Object> list1 = Lists.newArrayList();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		list1.add("c");
+		list1.add("c");
+
+		List<Object> list2 = Lists.newArrayList();
+		list2.add("c");
+		list2.add("b");
+		list2.add("a");
+
+		List<Object> result = collectionServices.add(list1, list2);
+		assertEquals(8, result.size());
+		assertEquals("a", result.get(0));
+		assertEquals("b", result.get(1));
+		assertEquals("c", result.get(2));
+		assertEquals("c", result.get(3));
+		assertEquals("c", result.get(4));
+		assertEquals("c", result.get(5));
+		assertEquals("b", result.get(6));
+		assertEquals("a", result.get(7));
+
+		Set<Object> set1 = Sets.newLinkedHashSet();
+		set1.add("c");
+		set1.add("b");
+		set1.add("a");
+
+		List<Object> result2 = collectionServices.add(list1, set1);
+		assertEquals(8, result2.size());
+		assertEquals("a", result2.get(0));
+		assertEquals("b", result2.get(1));
+		assertEquals("c", result2.get(2));
+		assertEquals("c", result2.get(3));
+		assertEquals("c", result2.get(4));
+		assertEquals("c", result2.get(5));
+		assertEquals("b", result2.get(6));
+		assertEquals("a", result2.get(7));
+	}
+
+	@Test
 	public void testSubList() {
 		List<Object> list1 = Lists.newArrayList();
 		List<Object> list2 = Lists.newArrayList();
@@ -276,6 +360,24 @@
 	}
 
 	@Test
+	public void testSubListWithDuplicates() {
+		List<Object> list1 = Lists.newArrayList();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		list1.add("c");
+		list1.add("c");
+
+		List<Object> list2 = Lists.newArrayList();
+		list2.add("c");
+
+		List<Object> result = collectionServices.sub(list1, list2);
+		assertEquals(2, result.size());
+		assertEquals("a", result.get(0));
+		assertEquals("b", result.get(1));
+	}
+
+	@Test
 	public void testAddSet() {
 		Set<Object> set1 = new HashSet<Object>();
 		Set<Object> set2 = new HashSet<Object>();
@@ -287,11 +389,11 @@
 		set1.add(obj1);
 		set1.add(obj2);
 		set2.add(obj3);
-		Set<Object> list3 = collectionServices.add(set1, set2);
-		assertEquals(3, list3.size());
-		assertTrue(list3.contains(obj1));
-		assertTrue(list3.contains(obj2));
-		assertTrue(list3.contains(obj3));
+		Set<Object> result = collectionServices.add(set1, set2);
+		assertEquals(3, result.size());
+		assertTrue(result.contains(obj1));
+		assertTrue(result.contains(obj2));
+		assertTrue(result.contains(obj3));
 
 		Set<Object> set3 = Sets.newLinkedHashSet();
 		set3.add(obj1);
@@ -1278,7 +1380,7 @@
 		assertEquals(1, result.size());
 		assertTrue(result.contains(EcorePackage.eINSTANCE));
 	}
-	
+
 	public void testFilterOnEContents_ecore_477217() {
 		EPackage rootPackage = EcoreFactory.eINSTANCE.createEPackage();
 		EPackage subPackage = EcoreFactory.eINSTANCE.createEPackage();