/*******************************************************************************
* 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.Iterator;
import org.rascalmpl.value.IList;
import org.rascalmpl.value.IListWriter;
import org.rascalmpl.value.ITuple;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.IValueFactory;
import org.rascalmpl.value.exceptions.FactTypeUseException;
import org.rascalmpl.value.type.Type;
import org.rascalmpl.value.type.TypeFactory;
import junit.framework.TestCase;
public abstract class BaseTestListRelation extends TestCase {
private IValueFactory vf;
private TypeFactory tf;
private IValue[] integers;
private ITuple[] integerTuples;
private IList listOfIntegers;
private IList integerListRelation;
private IValue[] doubles;
private IList listOfDoubles;
private IList doubleListRelation;
private ITuple[] doubleTuples;
protected void setUp(IValueFactory factory) throws Exception {
super.setUp();
vf = factory;
tf = TypeFactory.getInstance();
integers = new IValue[5];
IListWriter lw = vf.listWriter(tf.integerType());
for (int i = 0; i < integers.length; i++) {
IValue iv = vf.integer(i);
integers[i] = iv;
lw.insert(iv);
}
listOfIntegers = lw.done();
doubles = new IValue[10];
IListWriter lw2 = vf.listWriter(tf.realType());
for (int i = 0; i < doubles.length; i++) {
IValue iv = vf.real(i);
doubles[i] = iv;
lw2.insert(iv);
}
listOfDoubles = lw2.done();
IListWriter rw = vf.listRelationWriter(tf.tupleType(tf.integerType(), tf.integerType()));
integerTuples = new ITuple[integers.length * integers.length];
for (int i = 0; i < integers.length; i++) {
for (int j = 0; j < integers.length; j++) {
ITuple t = vf.tuple(integers[i], integers[j]);
integerTuples[i * integers.length + j] = t;
rw.insert(t);
}
}
integerListRelation = rw.done();
IListWriter rw2 = vf.listRelationWriter(tf.tupleType(tf.realType(), tf.realType()));
doubleTuples = new ITuple[doubles.length * doubles.length];
for (int i = 0; i < doubles.length; i++) {
for (int j = 0; j < doubles.length; j++) {
ITuple t = vf.tuple(doubles[i], doubles[j]);
doubleTuples[i * doubles.length + j] = t;
rw2.insert(t);
}
}
doubleListRelation = rw2.done();
}
public void testIsEmpty() {
if (integerListRelation.isEmpty()) {
fail("integerRelation is not empty");
}
if (!vf.listRelation(tf.tupleType(tf.integerType())).isEmpty()) {
fail("this relation should be empty");
}
IList emptyRel = vf.listRelation();
if (!emptyRel.isEmpty()) {
fail("empty relation is not empty?");
}
if (!emptyRel.getType().isListRelation()) {
fail("empty relation should have relation type");
}
}
public void testSize() {
if (integerListRelation.length() != integerTuples.length) {
fail("relation size is not correct");
}
}
public void testArity() {
if (integerListRelation.asRelation().arity() != 2) {
fail("arity should be 2");
}
}
public void testProductIRelation() {
IList prod = integerListRelation.product(integerListRelation);
if (prod.asRelation().arity() != 2 ) {
fail("arity of product should be 2");
}
if (prod.length() != integerListRelation.length() * integerListRelation.length()) {
fail("size of product should be square of size of integerRelation");
}
}
public void testProductIList() {
IList prod = integerListRelation.product(listOfIntegers);
if (prod.asRelation().arity() != 2) {
fail("arity of product should be 2");
}
if (prod.length() != integerListRelation.length() * listOfIntegers.length()) {
fail("size of product should be square of size of integerRelation");
}
}
public void testClosure() {
try {
if (!integerListRelation.asRelation().closure().isEqual(integerListRelation)) {
fail("closure adds extra tuples?");
}
} catch (FactTypeUseException e) {
fail("integerRelation is reflexive, so why an error?");
}
try {
ITuple t1 = vf.tuple(integers[0], integers[1]);
IList rel = vf.listRelation(t1);
rel.asRelation().closure();
}
catch (FactTypeUseException e) {
fail("reflexivity with subtyping is allowed");
}
try {
ITuple t1 = vf.tuple(integers[0], integers[1]);
ITuple t2 = vf.tuple(integers[1], integers[2]);
ITuple t3 = vf.tuple(integers[2], integers[3]);
ITuple t4 = vf.tuple(integers[0], integers[2]);
ITuple t5 = vf.tuple(integers[1], integers[3]);
ITuple t6 = vf.tuple(integers[0], integers[3]);
IList test = vf.listRelation(t1, t2, t3);
IList closed = test.asRelation().closure();
if (closed.asRelation().arity() != test.asRelation().arity()) {
fail("closure should produce relations of same arity");
}
if (closed.length() != 6) {
fail("closure contains too few elements");
}
if (!closed.intersect(test).isEqual(test)) {
fail("closure should contain all original elements");
}
if (!closed.contains(t4) || !closed.contains(t5) || !closed.contains(t6)) {
fail("closure does not contain required elements");
}
} catch (FactTypeUseException e) {
fail("this should all be type correct");
}
}
public void testCompose() {
try {
IList comp = integerListRelation.asRelation().compose(integerListRelation.asRelation());
if (comp.asRelation().arity() != integerListRelation.asRelation().arity() * 2 - 2) {
fail("composition is a product with the last column of the first relation and the first column of the last relation removed");
}
if (comp.length() != integerListRelation.length() * integers.length) {
fail("number of expected tuples is off");
}
} catch (FactTypeUseException e) {
fail("the above should be type correct");
}
try {
ITuple t1 = vf.tuple(integers[0], doubles[0]);
ITuple t2 = vf.tuple(integers[1], doubles[1]);
ITuple t3 = vf.tuple(integers[2], doubles[2]);
IList rel1 = vf.listRelation(t1, t2, t3);
ITuple t4 = vf.tuple(doubles[0], integers[0]);
ITuple t5 = vf.tuple(doubles[1], integers[1]);
ITuple t6 = vf.tuple(doubles[2], integers[2]);
IList rel2 = vf.listRelation(t4, t5, t6);
ITuple t7 = vf.tuple(integers[0], integers[0]);
ITuple t8 = vf.tuple(integers[1], integers[1]);
ITuple t9 = vf.tuple(integers[2], integers[2]);
IList rel3 = vf.listRelation(t7, t8, t9);
try {
vf.listRelation(vf.tuple(doubles[0],doubles[0])).asRelation().compose(rel1.asRelation());
fail("relations should not be composable");
}
catch (FactTypeUseException e) {
// this should happen
}
IList comp = rel1.asRelation().compose(rel2.asRelation());
if (!comp.isEqual(rel3)) {
fail("composition does not produce expected result");
}
} catch (FactTypeUseException e) {
fail("the above should be type correct");
}
}
public void testContains() {
try {
for (ITuple t : integerTuples) {
if (!integerListRelation.contains(t)) {
fail("contains returns false instead of true");
}
}
} catch (FactTypeUseException e) {
fail("this should be type correct");
}
}
public void testInsert() {
try {
// IList rel = integerListRelation.insert(vf.tuple(vf.integer(0),vf.integer(0)));
//
// if (!rel.isEqual(integerListRelation)) {
// fail("insert into a relation of an existing tuple should not change the relation");
// }
IListWriter relw3 = vf.listRelationWriter(tf.tupleType(tf.integerType(), tf.integerType()));
relw3.insertAll(integerListRelation);
IList rel3 = relw3.done();
final ITuple tuple = vf.tuple(vf.integer(100), vf.integer(100));
IList rel4 = rel3.insert(tuple);
if (rel4.length() != integerListRelation.length() + 1) {
fail("insert failed");
}
if (!rel4.contains(tuple)) {
fail("insert failed");
}
} catch (FactTypeUseException e) {
fail("the above should be type correct");
}
}
public void testIntersectIRelation() {
IList empty1 = vf.listRelation(tf.tupleType(tf.integerType()));
IList empty2 = vf.listRelation(tf.tupleType(tf.realType()));
try {
final IList intersection = empty1.intersect(empty2);
if (!intersection.isEmpty()) {
fail("empty intersection failed");
}
Type type = intersection.getType();
if (!type.getFieldType(0).isBottom()) {
fail("intersection should produce lub types");
}
} catch (FactTypeUseException e) {
fail("intersecting types which have a lub should be possible");
}
try {
if (!integerListRelation.intersect(doubleListRelation).isEmpty()) {
fail("non-intersecting relations should produce empty intersections");
}
IList oneTwoThree = vf.listRelation(integerTuples[0],
integerTuples[1], integerTuples[2]);
IList threeFourFive = vf.listRelation(integerTuples[2],
integerTuples[3], integerTuples[4]);
IList result = vf.listRelation(integerTuples[2]);
if (!oneTwoThree.intersect(threeFourFive).isEqual(result)) {
fail("intersection failed");
}
if (!threeFourFive.intersect(oneTwoThree).isEqual(result)) {
fail("intersection should be commutative");
}
if (!oneTwoThree.intersect(vf.listRelation(tf.tupleType(tf.integerType(),tf.integerType()))).isEmpty()) {
fail("intersection with empty set should produce empty");
}
} catch (FactTypeUseException e) {
fail("the above should all be type safe");
}
}
public void testIntersectIList() {
IList empty1 = vf.listRelation(tf.tupleType(tf.integerType()));
IList empty2 = vf.list(tf.tupleType(tf.realType()));
try {
final IList intersection = empty1.intersect(empty2);
if (!intersection.isEmpty()) {
fail("empty intersection failed");
}
Type type = intersection.getType();
if (!type.getFieldType(0).isBottom()) {
fail("empty intersection should produce void type");
}
} catch (FactTypeUseException e) {
fail("intersecting types which have a lub should be possible");
}
try {
if (!integerListRelation.intersect(doubleListRelation).isEmpty()) {
fail("non-intersecting relations should produce empty intersections");
}
IList oneTwoThree = vf.listRelation(integerTuples[0],
integerTuples[1], integerTuples[2]);
IList threeFourFive = vf.list(integerTuples[2],
integerTuples[3], integerTuples[4]);
IList result = vf.listRelation(integerTuples[2]);
if (!oneTwoThree.intersect(threeFourFive).isEqual(result)) {
fail("intersection failed");
}
if (!threeFourFive.intersect(oneTwoThree).isEqual(result)) {
fail("intersection should be commutative");
}
if (!oneTwoThree.intersect(vf.listRelation(tf.tupleType(tf.integerType(),tf.integerType()))).isEmpty()) {
fail("intersection with empty list should produce empty");
}
} catch (FactTypeUseException e) {
fail("the above should all be type safe");
}
}
public void testConcatIListRelation() {
IList empty1 = vf.listRelation(tf.tupleType(tf.integerType()));
IList empty2 = vf.listRelation(tf.tupleType(tf.realType()));
try {
final IList concat = (IList) empty1.concat(empty2);
if (!concat.isEmpty()) {
fail("empty concat failed");
}
Type type = concat.getType();
if (!type.getFieldType(0).isBottom()) {
fail("concat should produce void type");
}
} catch (FactTypeUseException e) {
fail("concat types which have a lub should be possible");
}
try {
if (integerListRelation.concat(doubleListRelation).length() != integerListRelation.length() + doubleListRelation.length()) {
fail("non-intersecting non-intersectiopn relations should produce relation that is the sum of the sizes");
}
IList oneTwoThree = vf.listRelation(integerTuples[0],
integerTuples[1], integerTuples[2]);
IList threeFourFive = vf.listRelation(integerTuples[3], integerTuples[4]);
IList result1 = vf.listRelation(integerTuples[0],
integerTuples[1], integerTuples[2], integerTuples[3], integerTuples[4]);
IList result2 = vf.listRelation(integerTuples[3],
integerTuples[4], integerTuples[0], integerTuples[1], integerTuples[2]);
if (!oneTwoThree.concat(threeFourFive).isEqual(result1)) {
fail("concat 1 failed");
}
if (!threeFourFive.concat(oneTwoThree).isEqual(result2)) {
fail("concat 2 failed");
}
if (!oneTwoThree.concat(vf.listRelation(tf.tupleType(tf.integerType(),tf.integerType()))).isEqual(oneTwoThree)) {
fail("concat with empty set should produce same set");
}
} catch (FactTypeUseException e) {
fail("the above should all be type safe");
}
}
public void testIterator() {
try {
Iterator<IValue> it = integerListRelation.iterator();
int i;
for (i = 0; it.hasNext(); i++) {
ITuple t = (ITuple) it.next();
if (!integerListRelation.contains(t)) {
fail("iterator produces strange elements?");
}
}
if (i != integerListRelation.length()) {
fail("iterator skipped elements");
}
} catch (FactTypeUseException e) {
fail("the above should be type correct");
}
}
public void testCarrier() {
IList carrier = integerListRelation.asRelation().carrier();
if (!carrier.isEqual(listOfIntegers)) {
fail("carrier should be equal to this set");
}
try {
ITuple t1 = vf.tuple(integers[0], doubles[0]);
ITuple t2 = vf.tuple(integers[1], doubles[1]);
ITuple t3 = vf.tuple(integers[2], doubles[2]);
IList rel1 = vf.listRelation(t1, t2, t3);
IList carrier1 = rel1.asRelation().carrier();
if (carrier1.getElementType() != tf.numberType()) {
fail("expected number type on carrier");
}
if (carrier1.length() != 6) {
fail("carrier does not contain all elements");
}
if (carrier1.intersect(listOfIntegers).length() != 3) {
fail("integers should be in there still");
}
if (carrier1.intersect(listOfDoubles).length() != 3) {
fail("doubles should be in there still");
}
} catch (FactTypeUseException e) {
fail("the above should be type correct");
}
}
}