Major refactoring to support coherent notifications - some known issues in JSON responses included
diff --git a/src/test/java/de/ids_mannheim/korap/collection/TestKorapCollectionJSON.java b/src/test/java/de/ids_mannheim/korap/collection/TestKorapCollectionJSON.java
index 32e22a3..b76adbe 100644
--- a/src/test/java/de/ids_mannheim/korap/collection/TestKorapCollectionJSON.java
+++ b/src/test/java/de/ids_mannheim/korap/collection/TestKorapCollectionJSON.java
@@ -46,6 +46,13 @@
 	assertEquals(kc.toString(), "filter with QueryWrapperFilter(+(pubDate:[19900000 TO 99999999] title:Mannheim)); ");
     };
 
+    @Test
+    public void nocollectiontypegiven () {
+	String metaQuery = _getJSONString("multiterm_rewrite_collection.jsonld");
+	KorapCollection kc = new KorapCollection(metaQuery);
+	assertEquals(701, kc.getError(0).getCode());
+    };
+
 
     @Ignore
     public void noCollection () {
diff --git a/src/test/java/de/ids_mannheim/korap/collection/TestKorapCollectionLegacy.java b/src/test/java/de/ids_mannheim/korap/collection/TestKorapCollectionLegacy.java
index 2cf0e4d..4a54d61 100644
--- a/src/test/java/de/ids_mannheim/korap/collection/TestKorapCollectionLegacy.java
+++ b/src/test/java/de/ids_mannheim/korap/collection/TestKorapCollectionLegacy.java
@@ -10,7 +10,6 @@
 import de.ids_mannheim.korap.KorapQuery;
 import de.ids_mannheim.korap.filter.BooleanFilter;
 
-
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.spans.SpanOrQuery;
 import org.apache.lucene.search.spans.SpanQuery;
@@ -31,7 +30,13 @@
 	// Construct index
 	KorapIndex ki = new KorapIndex();
 	// Indexing test files
-	for (String i : new String[] {"00001", "00002", "00003", "00004", "00005", "00006", "02439"}) {
+	for (String i : new String[] {"00001",
+				      "00002",
+				      "00003",
+				      "00004",
+				      "00005",
+				      "00006",
+				      "02439"}) {
 	    ki.addDocFile(
 	        getClass().getResource("/wiki/" + i + ".json.gz").getFile(), true
             );
@@ -48,7 +53,10 @@
 	// The virtual collection consists of all documents that have
 	// the textClass "reisen" and "freizeit"
 
-	kc.filter( kf.and("textClass", "reisen").and("textClass", "freizeit-unterhaltung") );
+	kc.filter(
+            kf.and("textClass", "reisen")
+	      .and("textClass", "freizeit-unterhaltung")
+	);
 
 	assertEquals("Documents", 5, kc.numberOf("documents"));
 	assertEquals("Tokens", 1678, kc.numberOf("tokens"));
diff --git a/src/test/java/de/ids_mannheim/korap/highlight/TestHighlight.java b/src/test/java/de/ids_mannheim/korap/highlight/TestHighlight.java
index 69cc84f..3e5bbf3 100644
--- a/src/test/java/de/ids_mannheim/korap/highlight/TestHighlight.java
+++ b/src/test/java/de/ids_mannheim/korap/highlight/TestHighlight.java
@@ -15,7 +15,6 @@
 import de.ids_mannheim.korap.util.QueryException;
 
 import static de.ids_mannheim.korap.TestSimple.*;
-//import static de.ids_mannheim.korap.Test.*;
 
 import static org.junit.Assert.*;
 import org.junit.Test;
@@ -52,18 +51,20 @@
 
 
 	KorapQuery kq = new KorapQuery("tokens");
-	KorapResult kr = ki.search((SpanQuery) kq.seq(kq._(1, kq.seg("s:b"))).toQuery());
+	KorapResult kr = ki.search(
+	    (SpanQuery) kq.seq(kq._(1, kq.seg("s:b"))).toQuery()
+        );
 	KorapMatch km = kr.getMatch(0);
-	assertEquals(km.getStartPos(), 1);
-	assertEquals(km.getEndPos(),   2);
+	assertEquals(km.getStartPos(),  1);
+	assertEquals(km.getEndPos(),    2);
 	assertEquals(km.getStartPos(1), 1);
 	assertEquals(km.getEndPos(1),   2);
 	assertEquals("<span class=\"context-left\">a</span><span class=\"match\"><em class=\"class-1 level-0\">b</em></span><span class=\"context-right\">c</span>", km.getSnippetHTML());
 
 	kr = ki.search((SpanQuery) kq.seq(kq._(1, kq.seg("s:b"))).append(kq._(2, kq.seg("s:c"))).toQuery());
 	km = kr.getMatch(0);
-	assertEquals(km.getStartPos(), 1);
-	assertEquals(km.getEndPos(),   3);
+	assertEquals(km.getStartPos(),  1);
+	assertEquals(km.getEndPos(),    3);
 	assertEquals(km.getStartPos(1), 1);
 	assertEquals(km.getEndPos(1),   2);
 	assertEquals(km.getStartPos(2), 2);
@@ -328,6 +329,9 @@
 
 	ks = new KorapSearch(json);
 	kr = ks.run(ki);
-	assertEquals(kr.getErrstr(),"Class numbers limited to 255");
+	assertEquals(709, kr.getError(0).getCode());
+	assertEquals("Valid class numbers exceeded", kr.getError(0).getMessage());
+
+	assertEquals(kr.getError(0).getMessage(),"Valid class numbers exceeded");
     };
 };
diff --git a/src/test/java/de/ids_mannheim/korap/query/TestKorapQueryJSON.java b/src/test/java/de/ids_mannheim/korap/query/TestKorapQueryJSON.java
index 4474b10..becff26 100644
--- a/src/test/java/de/ids_mannheim/korap/query/TestKorapQueryJSON.java
+++ b/src/test/java/de/ids_mannheim/korap/query/TestKorapQueryJSON.java
@@ -309,7 +309,7 @@
 	    new KorapQuery("tokens").fromJSON(json);
 	}
 	catch (QueryException e) {
-	    assertEquals(612, e.getErrorCode());
+	    assertEquals(701, e.getErrorCode());
 	};
     };
 
diff --git a/src/test/java/de/ids_mannheim/korap/query/TestTemporaryQueryLimitations.java b/src/test/java/de/ids_mannheim/korap/query/TestTemporaryQueryLimitations.java
index b015091..608c9de 100644
--- a/src/test/java/de/ids_mannheim/korap/query/TestTemporaryQueryLimitations.java
+++ b/src/test/java/de/ids_mannheim/korap/query/TestTemporaryQueryLimitations.java
@@ -57,10 +57,11 @@
 	assertEquals(kr.getQuery(),"shrink(130: {131: spanContain({129: <tokens:s />}, {130: tokens:s:wegen})})");
 	assertEquals(kr.totalResults(),0);
 	assertEquals(kr.getStartIndex(),0);
-	assertEquals(
-	    kr.getWarning(),
-	    "classRefCheck is not yet supported - results may not be correct; " +
-	    "This is a warning coming from the serialization");
 
+	assertEquals("This is a warning coming from the serialization",
+		     kr.getWarning(1).getMessage());
+	assertEquals("Class reference checks are currently not supported" +
+		     " - results may not be correct",
+		     kr.getWarning(0).getMessage());
     };
 };
diff --git a/src/test/java/de/ids_mannheim/korap/response/TestMessage.java b/src/test/java/de/ids_mannheim/korap/response/TestMessage.java
new file mode 100644
index 0000000..c8876ad
--- /dev/null
+++ b/src/test/java/de/ids_mannheim/korap/response/TestMessage.java
@@ -0,0 +1,38 @@
+package de.ids_mannheim.korap.util;
+import de.ids_mannheim.korap.response.Messages;
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+import org.junit.Ignore;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class TestMessage {
+
+    @Test
+    public void StringMessage () {
+	Messages km = new Messages();
+	assertEquals("[]", km.toJSON());
+    };
+
+    @Test
+    public void StringMessageSet () {
+	Messages km = new Messages();
+	km.add(612,"Foo");
+	assertEquals("[[612,\"Foo\"]]", km.toJSON());
+	km.add(613,"Bar");
+	assertEquals("[[612,\"Foo\"],[613,\"Bar\"]]", km.toJSON());
+    };
+
+    @Test
+    public void StringMessageParameters () {
+	Messages km = new Messages();
+	km.add(612,"Foo");
+	assertEquals("[[612,\"Foo\"]]", km.toJSON());
+	km.add(613,"Bar", "Instanz");
+	assertEquals("[[612,\"Foo\"],[613,\"Bar\",\"Instanz\"]]", km.toJSON());
+	km.add(614,"Test");
+	assertEquals("[[612,\"Foo\"],[613,\"Bar\",\"Instanz\"],[614,\"Test\"]]", km.toJSON());
+    };
+};
diff --git a/src/test/java/de/ids_mannheim/korap/response/TestNotifications.java b/src/test/java/de/ids_mannheim/korap/response/TestNotifications.java
new file mode 100644
index 0000000..e2982e1
--- /dev/null
+++ b/src/test/java/de/ids_mannheim/korap/response/TestNotifications.java
@@ -0,0 +1,205 @@
+package de.ids_mannheim.korap.util;
+
+import java.io.*;
+
+import de.ids_mannheim.korap.response.Messages;
+import de.ids_mannheim.korap.response.Notifications;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+import org.junit.Ignore;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class TestNotifications {
+
+    ObjectMapper mapper = new ObjectMapper();
+
+    @Test
+    public void testNotification () {
+	Notifications notes = new Notifications();
+	assertEquals("{}", notes.toJSON());
+    };
+
+    @Test
+    public void testNotificationWarnings () throws IOException {
+	Notifications notes = new Notifications();
+	assertFalse(notes.hasWarnings());
+	assertFalse(notes.hasMessages());
+	assertFalse(notes.hasErrors());
+
+	notes.addWarning(613, "Foo");
+	notes.addWarning(614, "Bar", "Spiel");
+
+	assertEquals("{\"warnings\":[[613,\"Foo\"],[614,\"Bar\"," +
+		     "\"Spiel\"]]}", notes.toJSON());
+
+	assertTrue(notes.hasWarnings());
+	assertFalse(notes.hasMessages());
+	assertFalse(notes.hasErrors());
+
+	notes.addError(412, "Test");
+
+	assertTrue(notes.hasWarnings());
+	assertFalse(notes.hasMessages());
+	assertTrue(notes.hasErrors());
+
+	JsonNode noteJson = mapper.readTree(notes.toJSON());
+
+	// {"warnings":[[613,"Foo"],[614,"Bar","Spiel"]],"errors":[[412,"Test"]]}
+	assertEquals(613, noteJson.at("/warnings/0/0").asInt());
+	assertEquals("Foo", noteJson.at("/warnings/0/1").asText());
+	assertEquals(614, noteJson.at("/warnings/1/0").asInt());
+	assertEquals("Bar", noteJson.at("/warnings/1/1").asText());
+	assertEquals("Spiel", noteJson.at("/warnings/1/2").asText());
+	assertEquals(412, noteJson.at("/errors/0/0").asInt());
+	assertEquals("Test", noteJson.at("/errors/0/1").asText());
+
+	notes.addMessage(567, "Probe", "huhu", "hihi");
+
+	assertTrue(notes.hasWarnings());
+	assertTrue(notes.hasMessages());
+	assertTrue(notes.hasErrors());
+
+	noteJson = mapper.readTree(notes.toJSON());
+
+	// {"warnings":[[613,"Foo"],[614,"Bar","Spiel"]],
+	// "errors":[[412,"Test"]]}
+	assertEquals(613, noteJson.at("/warnings/0/0").asInt());
+	assertEquals("Foo", noteJson.at("/warnings/0/1").asText());
+	assertEquals(614, noteJson.at("/warnings/1/0").asInt());
+	assertEquals("Bar", noteJson.at("/warnings/1/1").asText());
+	assertEquals("Spiel", noteJson.at("/warnings/1/2").asText());
+	assertEquals(412, noteJson.at("/errors/0/0").asInt());
+	assertEquals("Test", noteJson.at("/errors/0/1").asText());
+	assertEquals(567, noteJson.at("/messages/0/0").asInt());
+	assertEquals("Probe", noteJson.at("/messages/0/1").asText());
+	assertEquals("huhu", noteJson.at("/messages/0/2").asText());
+	assertEquals("hihi", noteJson.at("/messages/0/3").asText());
+
+	// Todo: Check how to check for missing node
+
+	Messages msgs = notes.getWarnings();
+	assertEquals("[[613,\"Foo\"],[614,\"Bar\",\"Spiel\"]]",
+		     msgs.toJSON());
+    };
+
+
+    @Test
+    public void testNotificationCopy () throws IOException {
+
+	Notifications notes1 = new Notifications();
+	notes1.addWarning(1, "Foo");
+	notes1.addWarning(2, "Bar", "Test");
+	notes1.addError(3, "Probe");
+
+	Notifications notes2 = new Notifications();
+	notes2.addMessage(4, "Krah");
+	notes2.addWarning(5, "Wu", "Niegel");
+
+	assertTrue(notes1.hasWarnings());
+	assertFalse(notes1.hasMessages());
+	assertTrue(notes1.hasErrors());
+
+	assertTrue(notes2.hasWarnings());
+	assertTrue(notes2.hasMessages());
+	assertFalse(notes2.hasErrors());
+
+	// Copy notations
+	notes1.copyNotificationsFrom(notes2);
+	assertTrue(notes1.hasWarnings());
+	assertTrue(notes1.hasMessages());
+	assertTrue(notes1.hasErrors());
+
+	JsonNode noteJson = mapper.readTree(notes1.toJSON());
+	assertEquals(1, noteJson.at("/warnings/0/0").asInt());
+	assertEquals("Foo", noteJson.at("/warnings/0/1").asText());
+	assertEquals(2, noteJson.at("/warnings/1/0").asInt());
+	assertEquals("Bar", noteJson.at("/warnings/1/1").asText());
+	assertEquals("Test", noteJson.at("/warnings/1/2").asText());
+	assertEquals(5, noteJson.at("/warnings/2/0").asInt());
+	assertEquals("Wu", noteJson.at("/warnings/2/1").asText());
+	assertEquals("Niegel", noteJson.at("/warnings/2/2").asText());
+	assertEquals(4, noteJson.at("/messages/0/0").asInt());
+	assertEquals("Krah", noteJson.at("/messages/0/1").asText());
+	assertEquals(3, noteJson.at("/errors/0/0").asInt());
+	assertEquals("Probe", noteJson.at("/errors/0/1").asText());
+    };
+
+    @Test
+    public void testNotificationJSONCopy () throws IOException {
+
+	Notifications notes1 = new Notifications();
+	notes1.addWarning(1, "Foo");
+	notes1.addWarning(2, "Bar", "Test");
+	notes1.addError(3, "Probe");
+
+	assertTrue(notes1.hasWarnings());
+	assertFalse(notes1.hasMessages());
+	assertTrue(notes1.hasErrors());
+
+	JsonNode noteJson = mapper.readTree(
+	    "{\"warnings\":[[5,\"Wu\",\"Niegel\"]]," +
+	    "\"messages\":[[4,\"Krah\"]]}"
+        );
+	notes1.copyNotificationsFrom(noteJson);
+
+	assertTrue(notes1.hasWarnings());
+	assertTrue(notes1.hasMessages());
+	assertTrue(notes1.hasErrors());
+
+	noteJson = mapper.readTree(notes1.toJSON());
+
+	assertEquals(1, noteJson.at("/warnings/0/0").asInt());
+	assertEquals("Foo", noteJson.at("/warnings/0/1").asText());
+	assertEquals(2, noteJson.at("/warnings/1/0").asInt());
+	assertEquals("Bar", noteJson.at("/warnings/1/1").asText());
+	assertEquals("Test", noteJson.at("/warnings/1/2").asText());
+	assertEquals(5, noteJson.at("/warnings/2/0").asInt());
+	assertEquals("Wu", noteJson.at("/warnings/2/1").asText());
+	assertEquals("Niegel", noteJson.at("/warnings/2/2").asText());
+
+	assertEquals(4, noteJson.at("/messages/0/0").asInt());
+	assertEquals("Krah", noteJson.at("/messages/0/1").asText());
+
+	assertEquals(3, noteJson.at("/errors/0/0").asInt());
+	assertEquals("Probe", noteJson.at("/errors/0/1").asText());
+
+	noteJson = mapper.readTree(
+	    "{\"warnings\":[[8, \"Tanja\", \"Gaby\"]],\"errors\":" +
+	    "[[\"Klößchen\"],[9,\"Karl\"]]}"
+        );
+	notes1.copyNotificationsFrom(noteJson);
+
+	assertTrue(notes1.hasWarnings());
+	assertTrue(notes1.hasMessages());
+	assertTrue(notes1.hasErrors());
+
+	noteJson = mapper.readTree(notes1.toJSON());
+
+	assertEquals(1, noteJson.at("/warnings/0/0").asInt());
+	assertEquals("Foo", noteJson.at("/warnings/0/1").asText());
+	assertEquals(2, noteJson.at("/warnings/1/0").asInt());
+	assertEquals("Bar", noteJson.at("/warnings/1/1").asText());
+	assertEquals("Test", noteJson.at("/warnings/1/2").asText());
+	assertEquals(5, noteJson.at("/warnings/2/0").asInt());
+	assertEquals("Wu", noteJson.at("/warnings/2/1").asText());
+	assertEquals("Niegel", noteJson.at("/warnings/2/2").asText());
+	assertEquals(8, noteJson.at("/warnings/3/0").asInt());
+	assertEquals("Tanja", noteJson.at("/warnings/3/1").asText());
+	assertEquals("Gaby", noteJson.at("/warnings/3/2").asText());
+
+	assertEquals(4, noteJson.at("/messages/0/0").asInt());
+	assertEquals("Krah", noteJson.at("/messages/0/1").asText());
+
+	assertEquals(3, noteJson.at("/errors/0/0").asInt());
+	assertEquals("Probe", noteJson.at("/errors/0/1").asText());
+	assertEquals("Klößchen", noteJson.at("/errors/1/0").asText());
+	assertEquals(9, noteJson.at("/errors/2/0").asInt());
+	assertEquals("Karl", noteJson.at("/errors/2/1").asText());
+    };
+};
diff --git a/src/test/java/de/ids_mannheim/korap/response/TestResponse.java b/src/test/java/de/ids_mannheim/korap/response/TestResponse.java
new file mode 100644
index 0000000..d7862ae
--- /dev/null
+++ b/src/test/java/de/ids_mannheim/korap/response/TestResponse.java
@@ -0,0 +1,84 @@
+package de.ids_mannheim.korap.util;
+
+import java.io.*;
+
+import de.ids_mannheim.korap.response.Messages;
+import de.ids_mannheim.korap.response.Notifications;
+import de.ids_mannheim.korap.response.KorapResponse;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+import org.junit.Ignore;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class TestResponse {
+
+    ObjectMapper mapper = new ObjectMapper();
+
+    @Test
+    public void testResponse () throws IOException {
+	KorapResponse resp = new KorapResponse();
+	assertEquals("{}", resp.toJSON());
+	resp.setVersion("0.24");
+	resp.setNode("Tanja");
+	assertEquals("0.24",resp.getVersion());
+	assertEquals("Tanja", resp.getNode());
+
+	assertFalse(resp.hasWarnings());
+	assertFalse(resp.hasMessages());
+	assertFalse(resp.hasErrors());
+
+	JsonNode respJson = mapper.readTree(resp.toJSON());
+	assertEquals("0.24", respJson.at("/version").asText());
+	assertEquals("Tanja", respJson.at("/node").asText());
+
+	resp.setName("Index");
+	respJson = mapper.readTree(resp.toJSON());
+	assertEquals("Index-0.24", respJson.at("/version").asText());
+	assertEquals("Tanja", respJson.at("/node").asText());
+
+	resp.setBenchmark("took a while");
+	resp.setListener("localhost:3000");
+	respJson = mapper.readTree(resp.toJSON());
+	assertEquals("localhost:3000", respJson.at("/listener").asText());
+	assertEquals("took a while", respJson.at("/benchmark").asText());
+    };
+
+    @Test
+    public void testResponseNotifications () throws IOException {
+	KorapResponse resp = new KorapResponse();
+	assertEquals("{}", resp.toJSON());
+	resp.setVersion("0.24");
+	resp.setNode("Tanja");
+	assertEquals("0.24",resp.getVersion());
+	assertEquals("Tanja", resp.getNode());
+
+	assertFalse(resp.hasWarnings());
+	assertFalse(resp.hasMessages());
+	assertFalse(resp.hasErrors());
+
+	JsonNode respJson = mapper.readTree(resp.toJSON());
+	assertEquals("0.24", respJson.at("/version").asText());
+	assertEquals("Tanja", respJson.at("/node").asText());
+
+	resp.addWarning(1, "Fehler 1");
+	resp.addWarning(2, "Fehler 2");
+	resp.addWarning(3, "Fehler 3");
+
+	resp.addError(4, "Fehler 4");
+
+	respJson = mapper.readTree(resp.toJSON());
+	assertEquals("0.24", respJson.at("/version").asText());
+	assertEquals("Tanja", respJson.at("/node").asText());
+
+	assertEquals("Fehler 1", respJson.at("/warnings/0/1").asText());
+	assertEquals("Fehler 2", respJson.at("/warnings/1/1").asText());
+	assertEquals("Fehler 3", respJson.at("/warnings/2/1").asText());
+	assertEquals("Fehler 4", respJson.at("/errors/0/1").asText());
+    };
+};
diff --git a/src/test/java/de/ids_mannheim/korap/search/TestKorapResult.java b/src/test/java/de/ids_mannheim/korap/search/TestKorapResult.java
index b353ee1..76f3736 100644
--- a/src/test/java/de/ids_mannheim/korap/search/TestKorapResult.java
+++ b/src/test/java/de/ids_mannheim/korap/search/TestKorapResult.java
@@ -118,7 +118,10 @@
 	ObjectMapper mapper = new ObjectMapper();
 	JsonNode res = mapper.readTree(kr.toJSON());
 
-	assertEquals("Optionality of query is ignored", res.at("/warning").asText());
+	// Old:
+	// assertEquals("Optionality of query is ignored", res.at("/warning").asText());
+	assertEquals("Optionality of query is ignored",
+		     res.at("/warnings/0/1").asText());
 
     };
 
@@ -149,7 +152,6 @@
 	// Commit!
 	ki.commit();
 
-
 	String json = getString(getClass().getResource("/queries/bsp-result-check.jsonld").getFile());
 	KorapSearch ks = new KorapSearch(json);
 	KorapResult kr = ks.run(ki);
diff --git a/src/test/java/de/ids_mannheim/korap/search/TestKorapSearch.java b/src/test/java/de/ids_mannheim/korap/search/TestKorapSearch.java
index 06908d7..240f33c 100644
--- a/src/test/java/de/ids_mannheim/korap/search/TestKorapSearch.java
+++ b/src/test/java/de/ids_mannheim/korap/search/TestKorapSearch.java
@@ -213,7 +213,7 @@
 	KorapResult kr = new KorapSearch("{ query").run(ki);
 
 	assertEquals(0, kr.getTotalResults());
-	assertNotNull(kr.getErr());
+	assertEquals(kr.getError(0).getMessage(), "Unable to parse JSON");
     };
 
 
@@ -763,8 +763,25 @@
         );
 	
 	KorapSearch ks = new KorapSearch(json);
+	KorapCollection kc = ks.getCollection();
+
+	// No index was set
+	assertEquals(-1, kc.numberOf("documents"));
+	kc.setIndex(ki);
+
+	// Index was set but vc restricted to WPD
+	assertEquals(0, kc.numberOf("documents"));
+
+	kc.extend(
+	    new KorapFilter().or("corpusSigle", "BZK")
+        );
+	/*
+	System.err.println(ks.getCollection().toString());
+	*/
+	assertEquals("Known issue: ", 1, kc.numberOf("documents"));
 
 	KorapResult kr = ks.run(ki);
+
 	assertEquals(
             kr.getQuery(),
 	    "spanOr([SpanMultiTermQueryWrapper(tokens:/tt/p:N.*/), " +
@@ -935,7 +952,9 @@
 	String json = getString(getClass().getResource("/queries/bsp-bug.jsonld").getFile());
 
 	KorapResult kr = new KorapSearch(json).run(ki);
-	assertEquals(kr.getErrstr(), "Operation needs exactly two operands");
+
+	assertEquals(kr.getError(0).getMessage(),
+		     "Number of operands is not acceptable");
     };
 
     /**
@@ -1010,11 +1029,7 @@
 	            getClass().getResource("/queries/bugs/expansion_bug.jsonld").getFile()
 	        );
 	
-		kr = new KorapSearch(json).run(ki);
-		// System.out.println(kr.getQuery());
-//		if (kr.getTotalResults() != 1)
-//		    fail("Expansion fails");
-	
+		kr = new KorapSearch(json).run(ki);	
 		assertEquals("... Buchstabe des Alphabetes. In Dänemark ist " +
 			     "[der alte Digraph Aa durch Å] ersetzt worden, " +
 			     "in Eigennamen und Ortsnamen ...",
diff --git a/src/test/java/de/ids_mannheim/korap/server/TestResource.java b/src/test/java/de/ids_mannheim/korap/server/TestResource.java
index 77c87bf..1096d89 100644
--- a/src/test/java/de/ids_mannheim/korap/server/TestResource.java
+++ b/src/test/java/de/ids_mannheim/korap/server/TestResource.java
@@ -24,7 +24,7 @@
 
 import de.ids_mannheim.korap.KorapNode;
 import de.ids_mannheim.korap.KorapResult;
-import de.ids_mannheim.korap.server.KorapResponse;
+import de.ids_mannheim.korap.response.KorapResponse;
 import static de.ids_mannheim.korap.util.KorapString.*;
 
 public class TestResource {
@@ -64,6 +64,8 @@
 
     @Test
     public void testResource() throws IOException {
+	KorapResponse kresp;
+
 	for (String i : new String[] {"00001",
 				      "00002",
 				      "00003",
@@ -74,18 +76,23 @@
 	    }) {
 
 	    String json = StringfromFile(getClass().getResource("/wiki/" + i + ".json").getFile());
-	    KorapResponse kresp = target.path("/index/" + i).
+	    kresp = target.path("/index/" + i).
 		request("application/json").
 		put(Entity.json(json), KorapResponse.class);
 
 	    assertEquals(kresp.getNode(), "milena");
-	    assertEquals(kresp.getErr(), 0);
+	    assertFalse(kresp.hasErrors());
+	    assertFalse(kresp.hasWarnings());
+	    assertFalse(kresp.hasMessages());
 	};
 
-	KorapResponse kresp = target.path("/index").
+	kresp = target.path("/index").
 	    request("application/json").
 	    post(Entity.text(""), KorapResponse.class);
 	assertEquals(kresp.getNode(), "milena");
+	assertFalse(kresp.hasErrors());
+	assertFalse(kresp.hasWarnings());
+	assertFalse(kresp.hasMessages());
     };
 
     @Test
@@ -101,9 +108,14 @@
 	    queryParam("uid", "4").
 	    request("application/json").
 	    post(Entity.json(json), KorapResponse.class);
-
+	 /*
 	 assertEquals(2, kresp.getTotalResults());
-	 assertEquals(0, kresp.getErr());
+	 */
+	 fail("totalResults should be implemented in KorapResponse" +
+	      " or KorapResult should be used here");
+	 assertFalse(kresp.hasErrors());
+	 assertFalse(kresp.hasWarnings());
+	 assertFalse(kresp.hasMessages());
     };
 
     public static String getString (String path) {
diff --git a/src/test/resources/index.properties b/src/test/resources/index.properties
index fa1fd47..b8b6980 100644
--- a/src/test/resources/index.properties
+++ b/src/test/resources/index.properties
@@ -1 +1,2 @@
-lucene.index.version = ${project.version}
+lucene.version = ${project.version}
+lucene.name = ${project.name}
diff --git a/src/test/resources/queries/bugs/cosmas_classrefcheck.jsonld b/src/test/resources/queries/bugs/cosmas_classrefcheck.jsonld
index bd0c08b..f4d6075 100644
--- a/src/test/resources/queries/bugs/cosmas_classrefcheck.jsonld
+++ b/src/test/resources/queries/bugs/cosmas_classrefcheck.jsonld
@@ -1,7 +1,7 @@
 {
   "@context": "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld",
   "warnings":[
-    "This is a warning coming from the serialization"
+      ["This is a warning coming from the serialization"]
   ],
   "query": {
     "@type" : "korap:reference",
diff --git a/src/test/resources/queries/bugs/multiterm_rewrite.jsonld b/src/test/resources/queries/bugs/multiterm_rewrite.jsonld
index c07f88c..6eec72e 100644
--- a/src/test/resources/queries/bugs/multiterm_rewrite.jsonld
+++ b/src/test/resources/queries/bugs/multiterm_rewrite.jsonld
@@ -5,7 +5,6 @@
   "announcements":[
     "Deprecated 2014-07-24: 'min' and 'max' to be supported until 3 months from deprecation date."
   ],
-  "collection":{},
   "meta":{
     "startPage":1,
     "context":"paragraph"
diff --git a/src/test/resources/queries/collections/multiterm_rewrite_collection.jsonld b/src/test/resources/queries/collections/multiterm_rewrite_collection.jsonld
new file mode 100644
index 0000000..c07f88c
--- /dev/null
+++ b/src/test/resources/queries/collections/multiterm_rewrite_collection.jsonld
@@ -0,0 +1,64 @@
+{
+  "@context":"http://ids-mannheim.de/ns/KorAP/json-ld/v0.2/context.jsonld",
+  "errors":[],
+  "warnings":[],
+  "announcements":[
+    "Deprecated 2014-07-24: 'min' and 'max' to be supported until 3 months from deprecation date."
+  ],
+  "collection":{},
+  "meta":{
+    "startPage":1,
+    "context":"paragraph"
+  },
+  "query":{
+    "@type":"korap:group",
+    "operation":"operation:sequence",
+    "operands":[
+      {
+	"@type":"korap:group",
+	"operation":"operation:repetition",
+	"operands":[
+	  {
+	    "@type":"korap:token",
+	    "wrap":{
+	      "@type":"korap:term",
+	      "foundry":"tt",
+	      "layer":"p",
+	      "type":"type:regex",
+	      "key":"A.*",
+	      "match":"match:eq"
+	    }
+	  }
+	],
+	"boundary":{
+	  "@type":"korap:boundary",
+	  "min":0,
+	  "max":3
+	},
+	"min":0,
+	"max":3
+      },
+      {
+	"@type":"korap:token",
+	"wrap":{
+	  "@type":"korap:term",
+	  "foundry":"tt",
+	  "layer":"p",
+	  "type":"type:regex",
+	  "key":"N.*",
+	  "match":"match:eq"
+	}
+      }
+    ]
+  },
+  "collections":[
+    {
+      "@type":"korap:meta-filter",
+      "@value":{
+	"@type":"korap:term",
+	"@field":"korap:field#corpusID",
+	"@value":"WPD"
+      }
+    }
+  ]
+}