diff --git a/tests/Makefile b/tests/Makefile
index f68b2175b344d635116286b8475cdc0d1ea08dca..0b9d3265bec7b925294981cfc55acd813c6519c9 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -2,3 +2,4 @@ all:
 	cd ../ && ./gradlew jar
 	cd valid && make test
 	cd errors && make test
+	cd multipleFiles && make test
diff --git a/tests/multipleFiles/.gitignore b/tests/multipleFiles/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..670d4423526234f1b4d5bfc56801b40603ac1e8b
--- /dev/null
+++ b/tests/multipleFiles/.gitignore
@@ -0,0 +1,3 @@
+/AST/*
+/*Gen.ast
+/*Gen.jadd
diff --git a/tests/multipleFiles/AbstractTests.java b/tests/multipleFiles/AbstractTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..3b86096602b5925e1bc0f41c7d75624404881bcb
--- /dev/null
+++ b/tests/multipleFiles/AbstractTests.java
@@ -0,0 +1,25 @@
+public class AbstractTests {
+	protected void assertException() {
+		check(false, "should throw exception");
+	}
+	protected void assertTrue(boolean b) {
+		check(b, "value should be true (is false)");
+	}
+	protected void assertFalse(boolean b) {
+		check(!b, "value should be flase (is true)");
+	}
+	protected void assertNull(Object obj) {
+		check(obj == null, "Object not null: " + obj);
+	}
+	protected void assertSame(Object o1, Object o2) {
+		check(o1 == o2, "Objects not same: " + o1 + ", " + o2);
+	}
+	protected void assertEquals(Object o1, Object o2) {
+		check(o1.equals(o2), "Objects not equals: " + o1 + ", " + o2);
+	}
+	protected void check(boolean b, String message) {
+		if (!b) {
+			throw new RuntimeException(message);
+		}
+	}
+}
\ No newline at end of file
diff --git a/tests/multipleFiles/All.java b/tests/multipleFiles/All.java
new file mode 100644
index 0000000000000000000000000000000000000000..80bddeaee6b683515fa37ed219273be48ca178a1
--- /dev/null
+++ b/tests/multipleFiles/All.java
@@ -0,0 +1,555 @@
+import AST.*;
+import java.util.*;
+
+@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
+public class All extends AbstractTests {
+	private Root r;
+	private A a1;
+	private A a2;
+	private A a3;
+	private B b1;
+	private B b2;
+	private B b3;
+
+	public static void main(String args[]) {
+		new All().test();
+	}
+
+	public void test() {
+		testDi1();
+		testDi2();
+		testDi3();
+
+		testBi1();
+		testBi2();
+		testBi3();
+		testBi4();
+		testBi5();
+		testBi6();
+		testBi7();
+		testBi8();
+		testBi9();
+
+		testImmutableList();
+	}
+
+	/**
+	 * rel A.di1 -> B;
+	 */
+	private void testDi1() {
+		setup();
+		a1.setDi1(b2);
+		a2.setDi1(b1);
+
+		assertSame(a1.di1(), b2);
+		assertSame(a2.di1(), b1);
+
+		a2.setDi1(b2);
+
+		assertSame(a1.di1(), b2);
+		assertSame(a2.di1(), b2);
+
+		try {
+			a3.setDi1(null);
+			assertException();
+		} catch (Exception e) {
+			// OK
+		}
+	}
+
+
+	/**
+	 * rel A.di2? -> B;
+	 */
+	private void testDi2() {
+		setup();
+		a1.setDi2(b2);
+		a2.setDi2(b1);
+
+		assertSame(a1.di2(), b2);
+		assertSame(a2.di2(), b1);
+
+		a2.setDi2(b2);
+
+		assertSame(a1.di2(), b2);
+		assertSame(a2.di2(), b2);
+
+		a2.clearDi2();
+
+		assertSame(a1.di2(), b2);
+		assertNull(a2.di2());
+
+		assertTrue(a1.hasDi2());
+		assertFalse(a2.hasDi2());
+		assertFalse(a3.hasDi2());
+	}
+
+
+	/**
+	 * rel A.di3* -> B;
+	 */
+	private void testDi3() {
+		setup();
+		a1.addToDi3(b1);
+		a1.addToDi3(b2);
+		a1.addToDi3(b3);
+		a2.addToDi3(b2);
+		
+		assertEquals(a1.di3(), Arrays.asList(b1, b2, b3));
+		assertEquals(a2.di3(), Arrays.asList(b2));
+		assertEquals(a3.di3(), Arrays.asList());
+
+		a1.addToDi3(b1);
+		a2.addToDi3(b1);
+		a2.addToDi3(b2);
+
+		assertEquals(a1.di3(), Arrays.asList(b1, b2, b3, b1));
+		assertEquals(a2.di3(), Arrays.asList(b2, b1, b2));
+		assertEquals(a3.di3(), Arrays.asList());
+
+		a1.removeFromDi3(b1);
+		a2.removeFromDi3(b2);
+
+		assertEquals(a1.di3(), Arrays.asList(b2, b3, b1));
+		assertEquals(a2.di3(), Arrays.asList(b1, b2));
+		assertEquals(a3.di3(), Arrays.asList());
+	}
+
+
+	/**
+	 * rel A.bi1 <-> B.bi1;
+	 */
+	private void testBi1() {
+		testBi11();
+		testBi12();
+	}
+	private void testBi11() {
+		// Init
+		setup();
+		a1.setBi1(b1);
+		a2.setBi1(b2);
+
+		// Change
+		a2.setBi1(b1);
+
+		assertNull(a1.bi1());
+		assertSame(a2.bi1(), b1);
+		assertSame(b1.bi1(), a2);
+		assertNull(b2.bi1());
+	}
+	private void testBi12() {
+		// Init
+		setup();
+		a1.setBi1(b2);
+
+		// Change
+		a2.setBi1(b2);
+
+		assertNull(a1.bi1());
+		assertSame(a2.bi1(), b2);
+		assertNull(b1.bi1());
+		assertSame(b2.bi1(), a2);
+	}
+
+
+
+	/**
+	 * rel A.bi2 <-> B.bi2?;
+	 */
+	private void testBi2() {
+		testBi21();
+		testBi22();
+	}
+	private void testBi21() {
+		// Init
+		setup();
+		a1.setBi2(b1);
+		a2.setBi2(b2);
+
+		// Change
+		a2.setBi2(b1);
+
+		assertNull(a1.bi2());
+		assertSame(a2.bi2(), b1);
+		assertSame(b1.bi2(), a2);
+		assertNull(b2.bi2());
+	}
+	private void testBi22() {
+		// Init
+		setup();
+		a1.setBi2(b2);
+
+		// Change
+		a2.setBi2(b2);
+
+		assertNull(a1.bi2());
+		assertSame(a2.bi2(), b2);
+		assertNull(b1.bi2());
+		assertSame(b2.bi2(), a2);
+	}
+
+
+
+	/**
+	 * rel A.bi3 <-> B.bi3*;
+	 */
+	private void testBi3() {
+		setup();
+		a2.setBi3(b2);
+
+		assertNull(a1.bi3());
+		assertSame(a2.bi3(), b2);
+		assertEquals(b1.bi3(), Arrays.asList());
+		assertEquals(b2.bi3(), Arrays.asList(a2));
+		assertEquals(b3.bi3(), Arrays.asList());
+
+		a2.setBi3(b3);
+
+		assertNull(a1.bi3());
+		assertSame(a2.bi3(), b3);
+		assertEquals(b1.bi3(), Arrays.asList());
+		assertEquals(b2.bi3(), Arrays.asList());
+		assertEquals(b3.bi3(), Arrays.asList(a2));
+
+		a1.setBi3(b3);
+		a3.setBi3(b3);
+
+		assertSame(a1.bi3(), b3);
+		assertSame(a2.bi3(), b3);
+		assertSame(a3.bi3(), b3);
+		assertEquals(b1.bi3(), Arrays.asList());
+		assertEquals(b2.bi3(), Arrays.asList());
+		assertEquals(b3.bi3(), Arrays.asList(a2, a1, a3));
+
+		a2.setBi3(b1);
+
+		assertSame(a1.bi3(), b3);
+		assertSame(a2.bi3(), b1);
+		assertSame(a3.bi3(), b3);
+		assertEquals(b1.bi3(), Arrays.asList(a2));
+		assertEquals(b2.bi3(), Arrays.asList());
+		assertEquals(b3.bi3(), Arrays.asList(a1, a3));
+
+		try {
+			a2.setBi3(null);
+			assertException();
+		} catch (Exception e) {
+			// OK
+		}
+	}
+
+
+
+	/**
+	 * rel A.bi4? <-> B.bi4;
+	 */
+	private void testBi4() {
+		testBi41();
+		testBi42();
+	}
+	private void testBi41() {
+		// Init
+		setup();
+		a1.setBi4(b1);
+		a2.setBi4(b2);
+
+		// Change
+		a2.setBi4(b1);
+
+		assertNull(a1.bi4());
+		assertSame(a2.bi4(), b1);
+		assertSame(b1.bi4(), a2);
+		assertNull(b2.bi4());
+	}
+	private void testBi42() {
+		// Init
+		setup();
+		a1.setBi4(b2);
+
+		// Change
+		a2.setBi4(b2);
+
+		assertNull(a1.bi4());
+		assertSame(a2.bi4(), b2);
+		assertNull(b1.bi4());
+		assertSame(b2.bi4(), a2);
+	}
+
+
+
+	/**
+	 * rel A.bi5? <-> B.bi5?;
+	 */
+	private void testBi5() {
+		testBi51();
+		testBi52();
+	}
+	private void testBi51() {
+		// Init
+		setup();
+		a1.setBi5(b1);
+		a2.setBi5(b2);
+
+		// Change
+		a2.setBi5(b1);
+
+		assertNull(a1.bi5());
+		assertSame(a2.bi5(), b1);
+		assertSame(b1.bi5(), a2);
+		assertNull(b2.bi5());
+	}
+	private void testBi52() {
+		// Init
+		setup();
+		a1.setBi5(b2);
+
+		// Change
+		a2.setBi5(b2);
+
+		assertNull(a1.bi5());
+		assertSame(a2.bi5(), b2);
+		assertNull(b1.bi5());
+		assertSame(b2.bi5(), a2);
+	}
+
+
+
+	/**
+	 * rel A.bi6? <-> B.bi6*;
+	 */
+	private void testBi6() {
+		setup();
+		a2.setBi6(b2);
+
+		assertNull(a1.bi6());
+		assertSame(a2.bi6(), b2);
+		assertEquals(b1.bi6(), Arrays.asList());
+		assertEquals(b2.bi6(), Arrays.asList(a2));
+		assertEquals(b3.bi6(), Arrays.asList());
+
+		a2.setBi6(b3);
+
+		assertNull(a1.bi6());
+		assertSame(a2.bi6(), b3);
+		assertEquals(b1.bi6(), Arrays.asList());
+		assertEquals(b2.bi6(), Arrays.asList());
+		assertEquals(b3.bi6(), Arrays.asList(a2));
+
+		a1.setBi6(b3);
+		a3.setBi6(b3);
+
+		assertSame(a1.bi6(), b3);
+		assertSame(a2.bi6(), b3);
+		assertSame(a3.bi6(), b3);
+		assertEquals(b1.bi6(), Arrays.asList());
+		assertEquals(b2.bi6(), Arrays.asList());
+		assertEquals(b3.bi6(), Arrays.asList(a2, a1, a3));
+
+		a2.setBi6(b1);
+
+		assertSame(a1.bi6(), b3);
+		assertSame(a2.bi6(), b1);
+		assertSame(a3.bi6(), b3);
+		assertEquals(b1.bi6(), Arrays.asList(a2));
+		assertEquals(b2.bi6(), Arrays.asList());
+		assertEquals(b3.bi6(), Arrays.asList(a1, a3));
+
+		a2.clearBi6();
+
+		assertSame(a1.bi6(), b3);
+		assertNull(a2.bi6());
+		assertSame(a3.bi6(), b3);
+		assertEquals(b1.bi6(), Arrays.asList());
+		assertEquals(b2.bi6(), Arrays.asList());
+		assertEquals(b3.bi6(), Arrays.asList(a1, a3));
+
+		assertTrue(a1.hasBi6());
+		assertFalse(a2.hasBi6());
+		assertTrue(a3.hasBi6());
+	}
+
+
+
+	/**
+	 * rel A.bi7* <-> B.bi7;
+	 */
+	private void testBi7() {
+		setup();
+		a2.addToBi7(b2);
+
+		assertEquals(a1.bi7(), Arrays.asList());
+		assertEquals(a2.bi7(), Arrays.asList(b2));
+		assertNull(b1.bi7());
+		assertSame(b2.bi7(), a2);
+		assertNull(b3.bi7());
+
+		a2.addToBi7(b3);
+		a1.addToBi7(b2);
+
+		assertEquals(a1.bi7(), Arrays.asList(b2));
+		assertEquals(a2.bi7(), Arrays.asList(b3));
+		assertNull(b1.bi7());
+		assertSame(b2.bi7(), a1);
+		assertSame(b3.bi7(), a2);
+
+		a1.addToBi7(b1);
+
+		assertEquals(a1.bi7(), Arrays.asList(b2, b1));
+		assertEquals(a2.bi7(), Arrays.asList(b3));
+		assertSame(b1.bi7(), a1);
+		assertSame(b2.bi7(), a1);
+		assertSame(b3.bi7(), a2);
+
+		a1.addToBi7(b1);
+
+		assertEquals(a1.bi7(), Arrays.asList(b2, b1));
+		assertEquals(a2.bi7(), Arrays.asList(b3));
+		assertSame(b1.bi7(), a1);
+		assertSame(b2.bi7(), a1);
+		assertSame(b3.bi7(), a2);
+
+		a1.removeFromBi7(b1);
+
+		assertEquals(a1.bi7(), Arrays.asList(b2));
+		assertEquals(a2.bi7(), Arrays.asList(b3));
+		assertNull(b1.bi7());
+		assertSame(b2.bi7(), a1);
+		assertSame(b3.bi7(), a2);
+	}
+
+
+
+	/**
+	 * rel A.bi8* <-> B.bi8?;
+	 */
+	private void testBi8() {
+		setup();
+		a2.addToBi8(b2);
+
+		assertEquals(a1.bi8(), Arrays.asList());
+		assertEquals(a2.bi8(), Arrays.asList(b2));
+		assertNull(b1.bi8());
+		assertSame(b2.bi8(), a2);
+		assertNull(b3.bi8());
+
+		a2.addToBi8(b3);
+		a1.addToBi8(b2);
+
+		assertEquals(a1.bi8(), Arrays.asList(b2));
+		assertEquals(a2.bi8(), Arrays.asList(b3));
+		assertNull(b1.bi8());
+		assertSame(b2.bi8(), a1);
+		assertSame(b3.bi8(), a2);
+
+		a1.addToBi8(b1);
+
+		assertEquals(a1.bi8(), Arrays.asList(b2, b1));
+		assertEquals(a2.bi8(), Arrays.asList(b3));
+		assertSame(b1.bi8(), a1);
+		assertSame(b2.bi8(), a1);
+		assertSame(b3.bi8(), a2);
+
+		a1.addToBi8(b1);
+
+		assertEquals(a1.bi8(), Arrays.asList(b2, b1));
+		assertEquals(a2.bi8(), Arrays.asList(b3));
+		assertSame(b1.bi8(), a1);
+		assertSame(b2.bi8(), a1);
+		assertSame(b3.bi8(), a2);
+
+		a1.removeFromBi8(b1);
+
+		assertEquals(a1.bi8(), Arrays.asList(b2));
+		assertEquals(a2.bi8(), Arrays.asList(b3));
+		assertNull(b1.bi8());
+		assertSame(b2.bi8(), a1);
+		assertSame(b3.bi8(), a2);
+	}
+
+
+
+	/**
+	 * rel A.bi9* <-> B.bi9*;
+	 */
+	private void testBi9() {
+		setup();
+		a1.addToBi9(b1);
+		a1.addToBi9(b2);
+
+		assertEquals(a1.bi9(), Arrays.asList(b1, b2));
+		assertEquals(a2.bi9(), Arrays.asList());
+		assertEquals(a3.bi9(), Arrays.asList());
+		assertEquals(b1.bi9(), Arrays.asList(a1));
+		assertEquals(b2.bi9(), Arrays.asList(a1));
+		assertEquals(b3.bi9(), Arrays.asList());
+	
+		b3.addToBi9(a1);
+		b3.addToBi9(a3);
+		b3.addToBi9(a1);
+
+		assertEquals(a1.bi9(), Arrays.asList(b1, b2, b3, b3));
+		assertEquals(a2.bi9(), Arrays.asList());
+		assertEquals(a3.bi9(), Arrays.asList(b3));
+		assertEquals(b1.bi9(), Arrays.asList(a1));
+		assertEquals(b2.bi9(), Arrays.asList(a1));
+		assertEquals(b3.bi9(), Arrays.asList(a1, a3, a1));
+
+		b3.removeFromBi9(a1);
+
+		assertEquals(a1.bi9(), Arrays.asList(b1, b2, b3));
+		assertEquals(a2.bi9(), Arrays.asList());
+		assertEquals(a3.bi9(), Arrays.asList(b3));
+		assertEquals(b1.bi9(), Arrays.asList(a1));
+		assertEquals(b2.bi9(), Arrays.asList(a1));
+		assertEquals(b3.bi9(), Arrays.asList(a3, a1));
+	}
+
+
+	public void testImmutableList() {
+		setup();
+
+		a1.addToDi3(b1);
+		a1.addToDi3(b2);
+		try {
+			a1.di3().add(b3);
+			assertException();
+		} catch (Exception e) {
+			// OK
+		}
+
+		a1.addToBi7(b1);
+		a1.addToBi7(b2);
+		try {
+			a1.bi7().add(b3);
+			assertException();
+		} catch (Exception e) {
+			// OK
+		}
+
+		a1.addToBi9(b1);
+		a1.addToBi9(b2);
+		try {
+			a1.bi9().add(b3);
+			assertException();
+		} catch (Exception e) {
+			// OK
+		}
+	}
+
+	private void setup() {
+		r = new Root();
+		a1 = new A("a1");
+		a2 = new A("a2");
+		a3 = new A("a3");
+		b1 = new B("b1");
+		b2 = new B("b2");
+		b3 = new B("b3");
+
+		r.addA(a1);
+		r.addA(a2);
+		r.addA(a3);
+		r.addB(b1);
+		r.addB(b2);
+		r.addB(b3);
+	}
+}
\ No newline at end of file
diff --git a/tests/multipleFiles/Makefile b/tests/multipleFiles/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d4564fe0830e683a3913dfc9c137855ee5ad914d
--- /dev/null
+++ b/tests/multipleFiles/Makefile
@@ -0,0 +1,17 @@
+all: build-jar test
+test: test1
+	@echo "#"
+	@echo "# MULTIPLE FILES TESTS OK"
+	@echo "#"
+
+build-jar:
+	(cd ../../ && ./gradlew jar)
+test1:
+	java -jar ../../build/libs/relast.jar Rules1.relast Rules2.relast Rules3.relast --file
+	rm -rf AST
+	rm -rf *.class
+	java -jar ../../tools/jastadd2.jar --package=AST Rules1Gen.ast Rules1Gen.jadd Utils.jadd
+	javac AST/*.java All.java
+	java All
+	java -jar ../../build/libs/relast.jar Rules1Gen.ast --file
+	diff Rules1Gen.ast Rules1GenGen.ast
\ No newline at end of file
diff --git a/tests/multipleFiles/Rules1.relast b/tests/multipleFiles/Rules1.relast
new file mode 100644
index 0000000000000000000000000000000000000000..a296c99ada58f8851ce55806e63fb731771b204d
--- /dev/null
+++ b/tests/multipleFiles/Rules1.relast
@@ -0,0 +1,5 @@
+B ::= <Name>;
+
+rel A.di1  -> B;
+rel A.di2? -> B;
+rel A.di3* -> B;
diff --git a/tests/multipleFiles/Rules2.relast b/tests/multipleFiles/Rules2.relast
new file mode 100644
index 0000000000000000000000000000000000000000..1733a7028590b9526a6e368ed7f6993c4a10714a
--- /dev/null
+++ b/tests/multipleFiles/Rules2.relast
@@ -0,0 +1,7 @@
+Root ::= A* B*;
+A ::= <Name>;
+
+
+rel A.bi1 <-> B.bi1;
+rel A.bi2 <-> B.bi2?;
+rel A.bi3 <-> B.bi3*;
diff --git a/tests/multipleFiles/Rules3.relast b/tests/multipleFiles/Rules3.relast
new file mode 100644
index 0000000000000000000000000000000000000000..1c94d76b54f399a8bc248e0c60d23306e9d7ec23
--- /dev/null
+++ b/tests/multipleFiles/Rules3.relast
@@ -0,0 +1,7 @@
+rel A.bi4? <-> B.bi4;
+rel A.bi5? <-> B.bi5?;
+rel A.bi6? <-> B.bi6*;
+
+rel A.bi7* <-> B.bi7;
+rel A.bi8* <-> B.bi8?;
+rel A.bi9* <-> B.bi9*;
diff --git a/tests/multipleFiles/Utils.jadd b/tests/multipleFiles/Utils.jadd
new file mode 100644
index 0000000000000000000000000000000000000000..d7acb1bd962911b580c0aa9f70f186727a42465f
--- /dev/null
+++ b/tests/multipleFiles/Utils.jadd
@@ -0,0 +1,9 @@
+aspect Utils {
+	public String A.toString() {
+		return getName();
+	}
+
+	public String B.toString() {
+		return getName();
+	}
+}
\ No newline at end of file