/*******************************************************************************
* Copyright (c) 2007 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation
*******************************************************************************/
package org.rascalmpl.value;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;
import org.rascalmpl.value.IList;
import org.rascalmpl.value.IListWriter;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.IValueFactory;
import org.rascalmpl.value.exceptions.FactTypeUseException;
import org.rascalmpl.value.type.TypeFactory;
import junit.framework.TestCase;
public abstract class BaseTestList extends TestCase {
private IValueFactory vf;
private TypeFactory tf = TypeFactory.getInstance();
private IValue[] integers;
private IList integerList;
private IList emptyIntegerList;
protected void setUp(IValueFactory factory) throws Exception {
super.setUp();
vf = factory;
integers = new IValue[20];
IListWriter w = vf.listWriter(tf.integerType());
for (int i = 0; i < integers.length; i++) {
integers[i] = vf.integer(i);
}
for (int i = integers.length - 1; i >= 0; i--) {
w.insert(vf.integer(i));
}
integerList = w.done();
emptyIntegerList = vf.listWriter(tf.integerType()).done();
}
public void testGetElementType() {
if (!integerList.getElementType().isSubtypeOf(tf.integerType())) {
fail("funny getElementType");
}
}
public void testAppend() {
try {
IValue newValue = vf.integer(integers.length);
IList longer = integerList.append(newValue);
if (longer.length() != integerList.length() + 1) {
fail("append failed");
}
if (!longer.get(integerList.length()).isEqual(newValue)) {
fail("element was not appended");
}
} catch (FactTypeUseException e) {
fail("the above should be type correct");
}
try {
if (!integerList.append(vf.real(2)).getElementType().equivalent(tf.numberType())) {
fail("append should lub the element type");
}
} catch (FactTypeUseException e) {
// this should happen
}
}
public void testGet() {
for (int i = 0; i < integers.length; i++) {
if (!integerList.get(i).isEqual(integers[i])) {
fail("get failed");
}
}
}
public void testInsert() {
try {
IValue newValue = vf.integer(integers.length);
IList longer = integerList.insert(newValue);
if (longer.length() != integerList.length() + 1) {
fail("append failed");
}
if (!longer.get(0).isEqual(newValue)) {
fail("element was not insrrted");
}
} catch (FactTypeUseException e) {
fail("the above should be type correct");
}
try {
if (!integerList.insert(vf.real(2)).getElementType().equivalent(tf.numberType())) {
fail("insert should lub the element type");
}
} catch (FactTypeUseException e) {
// this should happen
}
}
public void testLength() {
if (vf.list(tf.integerType()).length() != 0) {
fail("empty list should be size 0");
}
if (integerList.length() != integers.length) {
fail("length does not count amount of elements");
}
}
public void testReverse() {
IList reverse = integerList.reverse();
if (reverse.getType() != integerList.getType()) {
fail("reverse should keep type");
}
if (reverse.length() != integerList.length()) {
fail("length of reverse is different");
}
for (int i = 0; i < integers.length; i++) {
if (!reverse.get(i).isEqual(integers[integers.length - i - 1])) {
fail("reverse did something funny: " + reverse + " is not reverse of " + integerList);
}
}
}
public void testShuffle() {
IList shuffle = integerList.shuffle(new Random());
if (shuffle.getType() != integerList.getType()) {
fail("shuffle should keep type");
}
if (shuffle.length() != integerList.length()) {
fail("length after shuffle is different");
}
}
// doesn't completly test distribution, but at least protects against some cases
public void testShuffleFirstLast() {
Set<IValue> first = new HashSet<>();
Set<IValue> last = new HashSet<>();
Random r = new Random();
for (int i=0; i < 20 * integerList.length(); i++) {
IList shuffled = integerList.shuffle(r);
first.add(shuffled.get(0));
last.add(shuffled.get(shuffled.length() - 1));
}
for (IValue v: integerList) {
if (!first.contains(v)) {
fail("The shuffle doesn't shuffle the first index correctly");
}
if (!last.contains(v)) {
fail("The shuffle doesn't shuffle the last index correctly");
}
}
}
public void testReverseEmpty() {
IList reverse = emptyIntegerList.reverse();
if (reverse.getType() != emptyIntegerList.getType()) {
fail("reverse should keep type");
}
if (reverse.length() != emptyIntegerList.length()) {
fail("length of reverse is different");
}
}
public void testIterator() {
Iterator<IValue> it = integerList.iterator();
int i;
for (i = 0; it.hasNext(); i++) {
IValue v = it.next();
if (!v.isEqual(integers[i])) {
fail("iterator does not iterate in order");
}
}
}
// NOTE: This is not a very good test, but sufficient for it's purpose.
public void testSubList(){
// Front
IListWriter flw = vf.listWriter(tf.integerType());
for(int i = 0; i < 20; i++){
flw.append(vf.integer(i));
}
IList fList = flw.done();
// Back
IListWriter blw = vf.listWriter(tf.integerType());
for(int i = 19; i >= 0; i--){
blw.insert(vf.integer(i));
}
IList bList = blw.done();
// Overlap
IListWriter olw = vf.listWriter(tf.integerType());
for(int i = 9; i >= 0; i--){
olw.insert(vf.integer(i));
}
for(int i = 10; i < 20; i++){
olw.append(vf.integer(i));
}
IList oList = olw.done();
IList fSubList = fList.sublist(0, 5);
IList bSubList = bList.sublist(0, 5);
IList oSubList = oList.sublist(0, 5);
checkSubListEquality(fSubList, bSubList, oSubList);
fSubList = fList.sublist(1, 5);
bSubList = bList.sublist(1, 5);
oSubList = oList.sublist(1, 5);
checkSubListEquality(fSubList, bSubList, oSubList);
fSubList = fList.sublist(0, 15);
bSubList = bList.sublist(0, 15);
oSubList = oList.sublist(0, 15);
checkSubListEquality(fSubList, bSubList, oSubList);
fSubList = fList.sublist(1, 15);
bSubList = bList.sublist(1, 15);
oSubList = oList.sublist(1, 15);
checkSubListEquality(fSubList, bSubList, oSubList);
fSubList = fList.sublist(5, 5);
bSubList = bList.sublist(5, 5);
oSubList = oList.sublist(5, 5);
checkSubListEquality(fSubList, bSubList, oSubList);
fSubList = fList.sublist(5, 10);
bSubList = bList.sublist(5, 10);
oSubList = oList.sublist(5, 10);
checkSubListEquality(fSubList, bSubList, oSubList);
fSubList = fList.sublist(15, 5);
bSubList = bList.sublist(15, 5);
oSubList = oList.sublist(15, 5);
checkSubListEquality(fSubList, bSubList, oSubList);
}
private static void checkSubListEquality(IList fList, IList bList, IList oList){
if(!fList.isEqual(bList) || !bList.isEqual(oList)) fail("IList#subList is broken: "+fList+" "+bList+" "+oList);
}
public void testIsSubListOf(){
IListWriter w = vf.listWriter(tf.integerType());
for (int i = integers.length - 1; i >= 0; i -= 2) {
w.insert(vf.integer(i));
}
IList even = w.done();
w = vf.listWriter(tf.integerType());
for (int i = integers.length - 2; i >= 0; i -= 2) {
w.insert(vf.integer(i));
}
IList odd = w.done();
if(!integerList.isSubListOf(integerList))
fail("integerList should be sublist of integerList");
if(!even.isSubListOf(integerList))
fail("even should be sublist of integerList");
if(!odd.isSubListOf(integerList))
fail("odd should be sublist of integerList");
if(integerList.isSubListOf(even))
fail("integerList cannot be sublist of even");
if(integerList.isSubListOf(odd))
fail("integerList cannot be sublist of odd");
if(even.isSubListOf(odd))
fail("even cannot be sublist of odd");
if(odd.isSubListOf(even))
fail("odd cannot be sublist of even");
IList L123 = vf.list(integers[1], integers[2], integers[3]);
IList L918273 = vf.list(integers[9], integers[1], integers[8],integers[2], integers[7], integers[3]);
IList L918372 = vf.list(integers[9], integers[1], integers[8],integers[3], integers[7], integers[2]);
if(!L123.isSubListOf(L918273))
fail("123 is sublist of 918273");
if(L123.isSubListOf(L918372))
fail("123 is not a sublist of 918372");
}
public void testSubtract(){
IList L12312 = vf.list(integers[1], integers[2], integers[3], integers[1], integers[2]);
IList L123 = vf.list(integers[1], integers[2], integers[3]);
IList L12 = vf.list(integers[1], integers[2]);
IList L321321 = vf.list(integers[3], integers[2], integers[1],integers[3], integers[2], integers[1]);
if(!checkListEquality(L12312.subtract(L123), L12))
fail("12312 subtract 123 should be 12");
if(!L12312.subtract(L321321).isEmpty())
fail("12312 subtract 123213213 should be empty");
}
private boolean checkListEquality(IList lst1, IList lst2){
return lst1.isSubListOf(lst2) && lst2.isSubListOf(lst2);
}
}