diff --git a/buildADQL.xml b/buildADQL.xml
index 7903db53c6c67c71fdbb1b094c884331f02eaaf1..7ce2e9a5029c9d33be3ed6df5d6555b8efe9e2ef 100644
--- a/buildADQL.xml
+++ b/buildADQL.xml
@@ -22,14 +22,33 @@
 	
 	<property name="adqlParserLink" value="adqlParser.jar" />
 	
+	<property name="testsDir" value="test" />
+	<property name="junitReportsDir" value="reports/adql" />
+	
 	<fail message="The property POSTGRES must be set! It provides the path toward a directory or a JAR which contains all classes inside org.postgresql.">
 		<condition><not><isset property="POSTGRES"/></not></condition>
 	</fail>
 	
+	<fail message="The property SERVLET-API must be set! It provides the path toward a directory or a JAR which contains all classes inside javax.servlet.">
+		<condition><not><isset property="SERVLET-API"/></not></condition>
+	</fail>
+	
+	<fail message="The property JUNIT-API must be set! It provides the path toward a directory or a JAR which contains all classes needed to use JUnit.">
+		<condition><not><isset property="JUNIT-API"/></not></condition>
+	</fail>
+	
+	<!-- CLASSPATHS -->
 	<path id="adql.classpath">
 		<pathelement location="${POSTGRES}" />
 	</path>
 	
+	<path id="junit.class.path">
+		<path refid="adql.classpath" />
+		<pathelement path="${JUNIT-API}" />
+		<pathelement location="bin" />
+	</path>
+	
+	<!-- START -->
 	<echo>ADQL LIBRARY VERSION = ${version}</echo>
 	
 	<!-- BUILD ALL TASK -->
@@ -38,7 +57,24 @@
 		<antcall target="cleanJavadocBuild" />
 	</target>
 	
-	<target name="cleanAll" depends="clean,cleanJavadoc" description="Delete all files generated by this ANT file for the set version." />
+	<target name="cleanAll" depends="clean,cleanJUnitReports,cleanJavadoc" description="Delete all files generated by this ANT file for the set version." />
+	
+	<!-- JUNIT VALIDATION -->
+	<target name="cleanJUnitReports" description="Clean the JUnit reports directory of the ADQL library ONLY.">
+			<delete dir="${junitReportsDir}" failonerror="false" />
+	</target>
+	
+	<target name="junitValidation" depends="cleanJUnitReports" description="Executes all JUnit tests before building the library and stop ANT at any error.">
+		<mkdir dir="${junitReportsDir}"/>
+		<junit errorproperty="adqlTestsFailure" failureproperty="adqlTestsFailure">
+			<classpath refid="junit.class.path" />
+			<formatter type="brief" usefile="yes" />
+			<batchtest todir="${junitReportsDir}">
+				<fileset dir="${testsDir}" includes="adql/**/Test*.java" />
+			</batchtest>
+		</junit>
+		<fail if="${adqlTestsFailure}" message="Failed JUnit validation for ADQL Lib.!" />
+	</target>
 			
 	<!-- LIB & SOURCES -->
 	<target name="clean" description="Delete the JARs for the library (classes), the runnable ADQL parser and for its sources for the set version.">
@@ -49,7 +85,7 @@
 		<delete dir="${compileDir}" failonerror="false" />
 	</target>
 	
-	<target name="compileLib" depends="clean" description="Build all the classes of the ADQL library. This target is particularly usefull because it lets highlighting missing dependencies.">
+	<target name="compileLib" depends="clean,junitValidation" description="Build all the classes of the ADQL library. This target is particularly usefull because it lets highlighting missing dependencies.">
 		<mkdir dir="${compileDir}" />
 		<javac destdir="${compileDir}" srcdir="${srcDir}" includes="${includesList}" includeantruntime="false">
 			<classpath refid="adql.classpath" />
diff --git a/buildTAP.xml b/buildTAP.xml
index 6f7ec0a810055ae4e78251e336fb2f5b21d3a8ac..4d1100ea392a726e64750234a5350a46a9ffd685 100644
--- a/buildTAP.xml
+++ b/buildTAP.xml
@@ -26,6 +26,11 @@
 	<property name="srcJarFile" value="${jarDest}/tap_src_${version}.jar" />
 	<property name="javadocJarFile" value="${jarDest}/tap_javadoc_${version}.jar" />
 	
+	<property name="testsDir" value="test" />
+	<property name="adqlJunitReportsDir" value="reports/adql" />
+	<property name="uwsJunitReportsDir" value="reports/uws" />
+	<property name="tapJunitReportsDir" value="reports/tap" />
+	
 	<fail message="The property POSTGRES must be set! It provides the path toward a directory or a JAR which contains all classes inside org.postgresql.">
 		<condition><not><isset property="POSTGRES"/></not></condition>
 	</fail>
@@ -37,7 +42,13 @@
 	<fail message="The property JUNIT-API must be set! It provides the path toward a directory or a JAR which contains all classes needed to use JUnit.">
 		<condition><not><isset property="JUNIT-API"/></not></condition>
 	</fail>
+
+	<fail message="The property JNDI-API must be set! It provides the path toward a directory or a JAR which contains all classes needed to use Simple-JNDI.">
+		<condition><not><isset property="JNDI-API"/></not></condition>
+	</fail>
 	
+
+	<!-- CLASSPATHS -->
 	<path id="tap.classpath">
 		<pathelement location="${cosJar}" />
 		<pathelement location="${jsonJar}" />
@@ -46,14 +57,9 @@
 		<pathelement location="${SERVLET-API}" />
 	</path>
 	
-	<!-- Define the classpath which includes the junit.jar and the classes after compiling-->
 	<path id="junit.class.path">
-		<pathelement location="${cosJar}" />
-		<pathelement location="${jsonJar}" />
-		<pathelement location="${stilJar}" />
-		<pathelement location="${POSTGRES}" />
-		<pathelement location="${SERVLET-API}" />
-		
+		<path refid="tap.classpath" />
+		<pathelement path="${JNDI-API}" />
 		<pathelement path="${JUNIT-API}" />
 		<pathelement location="bin" />
 	</path>
@@ -66,25 +72,43 @@
 		<antcall target="cleanJavadocBuild" />
 	</target>
 	
-	<target name="cleanAll" depends="clean,cleanJavadoc" description="Delete all files generated by this ANT file for the set version." />
+	<target name="cleanAll" depends="clean,cleanJavadoc,cleanJUnitReports" description="Delete all files generated by this ANT file for the set version." />
+	
+	<!-- JUNIT VALIDATION -->
+	<target name="cleanJUnitReports" description="Clean the JUnit reports directory of the ADQL, UWS and TAP library ONLY.">
+		<delete dir="${adqlJunitReportsDir}" failonerror="false" />
+		<delete dir="${uwsJunitReportsDir}" failonerror="false" />
+		<delete dir="${tapJunitReportsDir}" failonerror="false" />
+	</target>
+	
+	<target name="junitValidation" depends="cleanJUnitReports" description="Executes all JUnit tests before building the library and stop ANT at any error.">
+		<mkdir dir="${adqlJunitReportsDir}"/>
+		<mkdir dir="${uwsJunitReportsDir}"/>
+		<mkdir dir="${tapJunitReportsDir}"/>
+		<junit errorproperty="testsFailure" failureproperty="testsFailure">
+			<classpath refid="junit.class.path" />
+			<formatter type="brief" usefile="yes" />
+			<batchtest todir="${adqlJunitReportsDir}">
+				<fileset dir="${testsDir}" includes="adql/**/Test*.java" />
+			</batchtest>
+			<batchtest todir="${uwsJunitReportsDir}">
+				<fileset dir="${testsDir}" includes="uws/**/Test*.java" />
+			</batchtest>
+			<batchtest todir="${tapJunitReportsDir}">
+				<fileset dir="${testsDir}" includes="tap/**/Test*.java" />
+			</batchtest>
+		</junit>
+		<fail if="${testsFailure}" message="Failed JUnit validation for ADQL, UWS or TAP Lib.!" />
+	</target>
 			
 	<!-- LIB & SOURCES -->
-	<target name="junitValidation" description="Executes all JUnit tests before building the library and stop ANT at any error.">
-			<junit printsummary="on" fork="yes" haltonfailure="yes">
-				<classpath refid="junit.class.path" />
-				<test name="tap.config.AllTests" outfile="testReports">
-					<formatter type="plain" usefile="yes" />
-				</test>
-			</junit>
-		</target>
-		
-		<target name="clean" depends="junitValidation" description="Delete the JARs for the library (classes) and for its sources for the set version.">
+	<target name="clean" depends="junitValidation" description="Delete the JARs for the library (classes) and for its sources for the set version.">
 		<delete file="${libJarFile}" failonerror="false" />
 		<delete file="${srcJarFile}" failonerror="false" />
 		<delete dir="${compileDir}" failonerror="false" />
 	</target>
 	
-	<target name="compileLib" depends="clean" description="Build all the classes of the TAP library. This target is particularly usefull because it lets highlighting missing dependencies.">
+	<target name="compileLib" depends="clean,junitValidation" description="Build all the classes of the TAP library. This target is particularly usefull because it lets highlighting missing dependencies.">
 		<mkdir dir="${compileDir}" />
 		<javac destdir="${compileDir}" srcdir="${srcDir}" includes="${includesList}" includeantruntime="false">
 			<classpath refid="tap.classpath" />
diff --git a/buildUWS.xml b/buildUWS.xml
index a4e0b350527de07924390ecb812dfe6ceef6752a..1322e2368d45914b1a6e884b56b59e44243692b7 100644
--- a/buildUWS.xml
+++ b/buildUWS.xml
@@ -24,15 +24,25 @@
 	<property name="srcJarFile" value="${jarDest}/uws_src_${version}.jar" />
 	<property name="javadocJarFile" value="${jarDest}/uws_javadoc_${version}.jar" />
 	
+	<property name="testsDir" value="test" />
+	<property name="junitReportsDir" value="reports/uws" />
+	
 	<fail message="The property SERVLET-API must be set! It provides the path toward a directory or a JAR which contains all classes inside javax.servlet.">
 		<condition><not><isset property="SERVLET-API"/></not></condition>
 	</fail>
-	
+
+	<!-- CLASSPATHS -->
 	<path id="uws.classpath">
 		<pathelement location="${cosJar}" />
 		<pathelement location="${SERVLET-API}" />
 	</path>
 	
+	<path id="junit.class.path">
+		<path refid="uws.classpath" />
+		<pathelement path="${JUNIT-API}" />
+		<pathelement location="bin" />
+	</path>
+	
 	<echo>UWS LIBRARY VERSION = ${version}</echo>
 	
 	<!-- BUILD ALL TASK -->
@@ -41,7 +51,24 @@
 		<antcall target="cleanJavadocBuild" />
 	</target>
 	
-	<target name="cleanAll" depends="clean,cleanJavadoc" description="Delete all files generated by this ANT file for the set version." />
+	<target name="cleanAll" depends="clean,cleanJavadoc,cleanJUnitReports" description="Delete all files generated by this ANT file for the set version." />
+	
+	<!-- JUNIT VALIDATION -->
+	<target name="cleanJUnitReports" description="Clean the JUnit reports directory of the UWS library ONLY.">
+			<delete dir="${junitReportsDir}" failonerror="false" />
+	</target>
+	
+	<target name="junitValidation" depends="cleanJUnitReports" description="Executes all JUnit tests before building the library and stop ANT at any error.">
+		<mkdir dir="${junitReportsDir}"/>
+		<junit errorproperty="uwsTestsFailure" failureproperty="uwsTestsFailure">
+			<classpath refid="junit.class.path" />
+			<formatter type="brief" usefile="yes" />
+			<batchtest todir="${junitReportsDir}">
+				<fileset dir="${testsDir}" includes="uws/**/Test*.java" />
+			</batchtest>
+		</junit>
+		<fail if="${uwsTestsFailure}" message="Failed JUnit validation for UWS Lib.!" />
+	</target>
 			
 	<!-- LIB & SOURCES -->
 	<target name="clean" description="Delete the JARs for the library (classes) and for its sources for the set version.">
@@ -50,7 +77,7 @@
 		<delete dir="${compileDir}" failonerror="false" />
 	</target>
 	
-	<target name="compileLib" depends="clean" description="Build all the classes of the UWS library. This target is particularly usefull because it lets highlighting missing dependencies.">
+	<target name="compileLib" depends="clean,junitValidation" description="Build all the classes of the UWS library. This target is particularly usefull because it lets highlighting missing dependencies.">
 		<mkdir dir="${compileDir}" />
 		<javac destdir="${compileDir}" srcdir="${srcDir}" includes="${includesList}" includeantruntime="false">
 			<classpath refid="uws.classpath" />
diff --git a/src/tap/resource/Capabilities.java b/src/tap/resource/Capabilities.java
index 7734dc4e80a7dbecd9443f03bdabca81eeeda086..4afdcca2b11eda6e39599be855025306f3d2bd2b 100644
--- a/src/tap/resource/Capabilities.java
+++ b/src/tap/resource/Capabilities.java
@@ -16,7 +16,7 @@ package tap.resource;
  * You should have received a copy of the GNU Lesser General Public License
  * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
  * 
- * Copyright 2012,2014 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ * Copyright 2012-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -38,7 +38,7 @@ import uk.ac.starlink.votable.VOSerializer;
  * <p>This resource just return an XML document giving a description of the TAP service and list all its VOSI resources.</p>
  * 
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.0 (09/2014)
+ * @version 2.0 (02/2015)
  */
 public class Capabilities implements TAPResource, VOSIResource {
 
@@ -128,7 +128,7 @@ public class Capabilities implements TAPResource, VOSIResource {
 		out.print(tap.getCapability());
 
 		// Write the capabilities of all VOSI resources:
-		Iterator<TAPResource> it = tap.getTAPResources();
+		Iterator<TAPResource> it = tap.getResources();
 		while(it.hasNext()){
 			TAPResource res = it.next();
 			if (res instanceof VOSIResource){
diff --git a/test/adql/SearchColumnListTest.java b/test/adql/SearchColumnListTest.java
deleted file mode 100644
index d3f614fb650fd9833f836fa84f1976de3238e07f..0000000000000000000000000000000000000000
--- a/test/adql/SearchColumnListTest.java
+++ /dev/null
@@ -1,243 +0,0 @@
-package adql;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import tap.metadata.TAPColumn;
-import tap.metadata.TAPSchema;
-import tap.metadata.TAPTable;
-import tap.metadata.TAPTable.TableType;
-import adql.db.DBColumn;
-import adql.db.DBCommonColumn;
-import adql.db.DBTable;
-import adql.db.DBType;
-import adql.db.SearchColumnList;
-import adql.db.DBType.DBDatatype;
-import adql.db.exception.UnresolvedJoin;
-import adql.parser.ParseException;
-import adql.query.IdentifierField;
-import adql.query.operand.ADQLColumn;
-
-public class SearchColumnListTest {
-
-	public static void main(String[] args) throws ParseException{
-
-		/* SET THE TABLES AND COLUMNS NEEDED FOR THE TEST */
-		// Describe the available table:
-		TAPTable tableA = new TAPTable("A", TableType.table, "NATURAL JOIN Test table", null);
-		TAPTable tableB = new TAPTable("B", TableType.table, "NATURAL JOIN Test table", null);
-		TAPTable tableC = new TAPTable("C", TableType.table, "NATURAL JOIN Test table", null);
-		TAPTable tableD = new TAPTable("D", TableType.table, "NATURAL JOIN Test table", null);
-
-		// Describe its columns:
-		tableA.addColumn(new TAPColumn("id", new DBType(DBDatatype.VARCHAR), "Object ID"));
-		tableA.addColumn(new TAPColumn("txta", new DBType(DBDatatype.VARCHAR), "Text of table A"));
-		tableB.addColumn(new TAPColumn("id", new DBType(DBDatatype.VARCHAR), "Object ID"));
-		tableB.addColumn(new TAPColumn("txtb", new DBType(DBDatatype.VARCHAR), "Text of table B"));
-		tableC.addColumn(new TAPColumn("Id", new DBType(DBDatatype.VARCHAR), "Object ID"));
-		tableC.addColumn(new TAPColumn("txta", new DBType(DBDatatype.VARCHAR), "Text of table A"));
-		tableC.addColumn(new TAPColumn("txtc", new DBType(DBDatatype.VARCHAR), "Text of table C"));
-		tableD.addColumn(new TAPColumn("id", new DBType(DBDatatype.VARCHAR), "Object ID"));
-		tableD.addColumn(new TAPColumn("txta", new DBType(DBDatatype.VARCHAR), "Text of table A"));
-		tableD.addColumn(new TAPColumn("txtd", new DBType(DBDatatype.VARCHAR), "Text of table D"));
-
-		// List all available tables:
-		TAPSchema schema = new TAPSchema("public");
-		schema.addTable(tableA);
-		schema.addTable(tableB);
-		schema.addTable(tableC);
-		schema.addTable(tableD);
-
-		// Build the corresponding SearchColumnList:
-		SearchColumnList listA = new SearchColumnList();
-		for(DBColumn col : tableA)
-			listA.add(col);
-		SearchColumnList listB = new SearchColumnList();
-		for(DBColumn col : tableB)
-			listB.add(col);
-		SearchColumnList listC = new SearchColumnList();
-		for(DBColumn col : tableC)
-			listC.add(col);
-		SearchColumnList listD = new SearchColumnList();
-		for(DBColumn col : tableD)
-			listD.add(col);
-
-		/* TEST OF NATURAL JOIN */
-		System.out.println("### CROSS JOIN ###");
-		SearchColumnList crossJoin = join(listA, listB, false, null);
-
-		// DEBUG
-		for(DBColumn dbCol : crossJoin){
-			if (dbCol instanceof DBCommonColumn){
-				System.out.print("\t- " + dbCol.getADQLName() + " in " + ((dbCol.getTable() == null) ? "<NULL>" : dbCol.getTable().getADQLName()) + " (= " + dbCol.getDBName() + " in ");
-				Iterator<DBTable> it = ((DBCommonColumn)dbCol).getCoveredTables();
-				DBTable table;
-				while(it.hasNext()){
-					table = it.next();
-					System.out.print((table == null) ? "<NULL>" : table.getDBName() + ", ");
-				}
-				System.out.println(")");
-			}else
-				System.out.println("\t- " + dbCol.getADQLName() + " in " + ((dbCol.getTable() == null) ? "<NULL>" : dbCol.getTable().getADQLName()) + " (= " + dbCol.getDBName() + " in " + ((dbCol.getTable() == null) ? "<NULL>" : dbCol.getTable().getDBName()) + ")");
-		}
-		System.out.println();
-
-		/* TEST OF NATURAL JOIN */
-		System.out.println("### NATURAL JOIN ###");
-		SearchColumnList join1 = join(listA, listB, true, null);
-		SearchColumnList join2 = join(listC, listD, true, null);
-		//SearchColumnList join3 = join(join1, join2, true, null);
-
-		// DEBUG
-		for(DBColumn dbCol : join2){
-			if (dbCol instanceof DBCommonColumn){
-				System.out.print("\t- " + dbCol.getADQLName() + " in " + ((dbCol.getTable() == null) ? "<NULL>" : dbCol.getTable().getADQLName()) + " (= " + dbCol.getDBName() + " in ");
-				Iterator<DBTable> it = ((DBCommonColumn)dbCol).getCoveredTables();
-				DBTable table;
-				while(it.hasNext()){
-					table = it.next();
-					System.out.print((table == null) ? "<NULL>" : table.getDBName() + ", ");
-				}
-				System.out.println(")");
-			}else
-				System.out.println("\t- " + dbCol.getADQLName() + " in " + ((dbCol.getTable() == null) ? "<NULL>" : dbCol.getTable().getADQLName()) + " (= " + dbCol.getDBName() + " in " + ((dbCol.getTable() == null) ? "<NULL>" : dbCol.getTable().getDBName()) + ")");
-		}
-		System.out.println();
-
-		/* TEST OF JOIN USING 1 */
-		System.out.println("\n### USING JOIN 1 ###");
-		ArrayList<ADQLColumn> usingList = new ArrayList<ADQLColumn>();
-		usingList.add(new ADQLColumn("id"));
-		SearchColumnList joinUsing1 = join(join1, join2, false, usingList);
-
-		// DEBUG
-		for(DBColumn dbCol : joinUsing1){
-			if (dbCol instanceof DBCommonColumn){
-				System.out.print("\t- " + dbCol.getADQLName() + " in " + ((dbCol.getTable() == null) ? "<NULL>" : dbCol.getTable().getADQLName()) + " (= " + dbCol.getDBName() + " in ");
-				Iterator<DBTable> it = ((DBCommonColumn)dbCol).getCoveredTables();
-				DBTable table;
-				while(it.hasNext()){
-					table = it.next();
-					System.out.print((table == null) ? "<NULL>" : table.getDBName() + ", ");
-				}
-				System.out.println(")");
-			}else
-				System.out.println("\t- " + dbCol.getADQLName() + " in " + ((dbCol.getTable() == null) ? "<NULL>" : dbCol.getTable().getADQLName()) + " (= " + dbCol.getDBName() + " in " + ((dbCol.getTable() == null) ? "<NULL>" : dbCol.getTable().getDBName()) + ")");
-		}
-		System.out.println();
-
-		/* TEST OF JOIN USING 1 *
-			System.out.println("\n### USING JOIN 2 ###");
-			usingList.clear();
-			usingList.add(new TAPColumn("id"));
-			SearchColumnList joinUsing2 = joinUsing(listA, join3, usingList);
-			
-		// DEBUG
-			for(DBColumn dbCol : joinUsing2){
-				System.out.println("\t- "+dbCol.getADQLName()+" in "+((dbCol.getTable()==null)?"<NULL>":dbCol.getTable().getADQLName())+" (= "+dbCol.getDBName()+" in "+((dbCol.getTable()==null)?"<NULL>":dbCol.getTable().getDBName())+")");
-			}
-			System.out.println();*/
-
-	}
-
-	public static final SearchColumnList join(final SearchColumnList leftList, final SearchColumnList rightList, final boolean natural, final ArrayList<ADQLColumn> usingList) throws UnresolvedJoin{
-
-		SearchColumnList list = new SearchColumnList();
-		/*SearchColumnList leftList = leftTable.getDBColumns();
-		SearchColumnList rightList = rightTable.getDBColumns();*/
-
-		/* 1. Figure out duplicated columns */
-		HashMap<String,DBCommonColumn> mapDuplicated = new HashMap<String,DBCommonColumn>();
-		// CASE: NATURAL
-		if (natural){
-			// Find duplicated items between the two lists and add one common column in mapDuplicated for each
-			DBColumn rightCol;
-			for(DBColumn leftCol : leftList){
-				// search for at most one column with the same name in the RIGHT list
-				// and throw an exception is there are several matches:
-				rightCol = findAtMostOneColumn(leftCol.getADQLName(), (byte)0, rightList, false);
-				// if there is one...
-				if (rightCol != null){
-					// ...check there is only one column with this name in the LEFT list,
-					// and throw an exception if it is not the case:
-					findExactlyOneColumn(leftCol.getADQLName(), (byte)0, leftList, true);
-					// ...create a common column:
-					mapDuplicated.put(leftCol.getADQLName().toLowerCase(), new DBCommonColumn(leftCol, rightCol));
-				}
-			}
-
-		}
-		// CASE: USING
-		else if (usingList != null && !usingList.isEmpty()){
-			// For each columns of usingList, check there is in each list exactly one matching column, and then, add it in mapDuplicated
-			DBColumn leftCol, rightCol;
-			for(ADQLColumn usingCol : usingList){
-				// search for exactly one column with the same name in the LEFT list
-				// and throw an exception if there is none, or if there are several matches:
-				leftCol = findExactlyOneColumn(usingCol.getColumnName(), usingCol.getCaseSensitive(), leftList, true);
-				// idem in the RIGHT list:
-				rightCol = findExactlyOneColumn(usingCol.getColumnName(), usingCol.getCaseSensitive(), rightList, false);
-				// create a common column:
-				mapDuplicated.put((usingCol.isCaseSensitive(IdentifierField.COLUMN) ? ("\"" + usingCol.getColumnName() + "\"") : usingCol.getColumnName().toLowerCase()), new DBCommonColumn(leftCol, rightCol));
-			}
-
-		}
-		// CASE: NO DUPLICATION TO FIGURE OUT
-		else{
-			// Return the union of both lists:
-			list.addAll(leftList);
-			list.addAll(rightList);
-			return list;
-		}
-
-		/* 2. Add all columns of the left list except the ones identified as duplications */
-		addAllExcept(leftList, list, mapDuplicated);
-
-		/* 3. Add all columns of the right list except the ones identified as duplications */
-		addAllExcept(rightList, list, mapDuplicated);
-
-		/* 4. Add all common columns of mapDuplicated */
-		list.addAll(mapDuplicated.values());
-
-		return list;
-
-	}
-
-	public final static void addAllExcept(final SearchColumnList itemsToAdd, final SearchColumnList target, final Map<String,DBCommonColumn> exception){
-		for(DBColumn col : itemsToAdd){
-			if (!exception.containsKey(col.getADQLName().toLowerCase()) && !exception.containsKey("\"" + col.getADQLName() + "\""))
-				target.add(col);
-		}
-	}
-
-	public final static DBColumn findExactlyOneColumn(final String columnName, final byte caseSensitive, final SearchColumnList list, final boolean leftList) throws UnresolvedJoin{
-		DBColumn result = findAtMostOneColumn(columnName, caseSensitive, list, leftList);
-		if (result == null)
-			throw new UnresolvedJoin("Column \"" + columnName + "\" specified in USING clause does not exist in " + (leftList ? "left" : "right") + " table!");
-		else
-			return result;
-	}
-
-	public final static DBColumn findAtMostOneColumn(final String columnName, final byte caseSensitive, final SearchColumnList list, final boolean leftList) throws UnresolvedJoin{
-		ArrayList<DBColumn> result = list.search(null, null, null, columnName, caseSensitive);
-		if (result.isEmpty())
-			return null;
-		else if (result.size() > 1)
-			throw new UnresolvedJoin("Common column name \"" + columnName + "\" appears more than once in " + (leftList ? "left" : "right") + " table!");
-		else
-			return result.get(0);
-	}
-
-	/**
-	 * Tells whether the given column is a common column (that's to say, a unification of several columns of the same name).
-	 * 
-	 * @param col	A DBColumn.
-	 * @return		true if the given column is a common column, false otherwise (particularly if col = null).
-	 */
-	public static final boolean isCommonColumn(final DBColumn col){
-		return (col != null && col instanceof DBCommonColumn);
-	}
-
-}
diff --git a/test/adql/SearchIterator.java b/test/adql/SearchIterator.java
deleted file mode 100644
index c36588209dedb161c47d46a7e3deaefdb731798d..0000000000000000000000000000000000000000
--- a/test/adql/SearchIterator.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package adql;
-
-/*
- * This file is part of ADQLLibrary.
- * 
- * ADQLLibrary is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * ADQLLibrary is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public License
- * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
- * 
- * Copyright 2011 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
- */
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.Vector;
-
-/**
- * Lets iterate on each "real" result <i>({@link SearchResult} objects whose the {@link SearchResult#isResult() isResult()} function returns </i>true<i>)</i>.
- * 
- * @author Gr&eacute;gory Mantelet (CDS)
- * @version 11/2010
- * 
- * @see SearchResult
- */
-public class SearchIterator implements Iterator<SearchResult> {
-
-	/** List of the next SearchResult objects which has at least one result (themselves or included SearchResult). */
-	protected Vector<SearchResult> toExplore;
-
-	public SearchIterator(SearchResult r){
-		toExplore = new Vector<SearchResult>();
-		if (r != null && r.hasResult())
-			toExplore.add(r);
-	}
-
-	public boolean hasNext(){
-		return !toExplore.isEmpty();
-	}
-
-	public SearchResult next() throws NoSuchElementException{
-		SearchResult next = null;
-
-		while(next == null && !toExplore.isEmpty()){
-			SearchResult r = toExplore.remove(0);
-			if (!r.isLeaf()){
-				Iterator<SearchResult> children = r.getChildren();
-				while(children.hasNext()){
-					SearchResult child = children.next();
-					if (child != null && child.hasResult())
-						toExplore.add(child);
-				}
-			}
-			if (r.isResult())
-				next = r;
-		}
-
-		if (next == null)
-			throw new NoSuchElementException("No more search result !");
-
-		return next;
-	}
-
-	public void remove() throws UnsupportedOperationException{
-		throw new UnsupportedOperationException("The REMOVE operation is not possible in a search result !");
-	}
-
-}
diff --git a/test/adql/SearchResult.java b/test/adql/SearchResult.java
deleted file mode 100644
index 3a373d8868c40ee83ab0baa3f75e1f40da44f6a6..0000000000000000000000000000000000000000
--- a/test/adql/SearchResult.java
+++ /dev/null
@@ -1,251 +0,0 @@
-package adql;
-
-/*
- * This file is part of ADQLLibrary.
- * 
- * ADQLLibrary is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * ADQLLibrary is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public License
- * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
- * 
- * Copyright 2011 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
- */
-
-import java.util.Iterator;
-import java.util.Vector;
-
-import adql.query.ADQLObject;
-
-/**
- * <p>Results of a research in an ADQL query.</p>
- * 
- * <p>This class is built as a tree. A node (leaf or not) corresponds to an item of a part of an ADQL query or merely of a whole ADQL query.
- * It represents a step of the research. That means a node can represents a matched ADQL item and/or a list of other SearchResults (which are the results of the same research into the corresponding ADQL object).
- * Thus it is possible to know the parent (into the ADQL query) of a matched ADQL item.</p>
- * 
- * <p>Here are some useful functions of this class:
- * <ul>
- * 	<li><u>{@link SearchResult#isResult() isResult()}:</u> indicates whether the current node corresponds to a matched ADQL item</li>
- * 	<li><u>{@link SearchResult#getResult() getResult()}:</u> returns the value of this node</li>
- * 	<li><u>{@link SearchResult#getParent() getParent()}:</u> returns the result (node) which encapsulates this result (node)</li>
- * 	<li><u>{@link SearchResult#isLeaf() isLeaf()}:</u> indicates whether this node encapsulates other results (nodes) or not</li>
- * 	<li><u>{@link SearchResult#getChildren() getChildren()}:</u> returns an iterator on all encapsulated results (nodes)</li>
- * </ul></p>
- * 
- * <p>You have two different ways to navigate in a SearchResult object:
- * <ol>
- * 	<li>As said previously a SearchResult is a hierarchical structure. So you can <b>explore it as a tree</b> with the functions {@link SearchResult#getResult() getResult()} (to get the node value), {@link SearchResult#getParent() getParent()} (to get the direct parent node), {@link SearchResult#getChildren() getChildren()} (to explore the children list) and {@link SearchResult#isLeaf() isLeaf()} (to determine if the current node is a leaf or not).</li>
- * 	<li>However you can also <b>iterate directly</b> on each matched ADQL item (leaf or not) thanks to the {@link SearchResult#iterator() iterator()} function. All iterated object corresponds to a matched ADQL object (so {@link SearchResult#isResult() isResult()} always returns <i>true</i> for all iterated results).</li>
- * </ol></p>
- *
- * <p><b><u>Important:</u> Be aware that any SearchResult (leaf or not) may contain a matched ADQL object: to know that, use the function {@link SearchResult#isResult() isResult()}.</b></p>
- * 
- * @author Gr&eacute;gory Mantelet (CDS)
- * @version 11/2010
- * 
- * @see SearchIterator
- */
-public final class SearchResult implements Iterable<SearchResult> {
-
-	/** Parent node. */
-	private SearchResult parent;
-
-	/** Child nodes. */
-	private final Vector<SearchResult> children;
-
-	/** Total number of results from this node (included). */
-	private int nbResults = 0;
-
-	/** The node value (may be the matched ADQL object). */
-	private final ADQLObject value;
-
-	/** Indicates whether this node corresponds to a matched ADQL object or not. */
-	private final boolean result;
-
-	/** If it is impossible to replace an ADQL object by another one, a SearchResult must be created (with result = true) and this field must contain an error description. */
-	private String error = null;
-
-	/**
-	 * <p>Builds a SearchResult (node) with its value (node value).</p>
-	 * <p><i><u>Note:</u> By using this constructor the created SearchResult will not correspond to a matched ADQL object.</i></p>
-	 * 
-	 * @param nodeValue	Value (ADQL object) associated with this node.
-	 */
-	public SearchResult(ADQLObject nodeValue){
-		this(nodeValue, false);
-	}
-
-	/**
-	 * Builds a SearchResult (node) with its value (node value) and an indication on its interpretation (~ "matched ADQL object ?").
-	 * 
-	 * @param nodeValue		Value (ADQL object) associated with this node.
-	 * @param isResult		Indicates whether the given ADQL object is a match or not.
-	 */
-	public SearchResult(ADQLObject nodeValue, boolean isResult){
-		this.parent = null;
-		children = new Vector<SearchResult>();
-
-		value = nodeValue;
-		result = (nodeValue != null) && isResult;
-		if (result)
-			nbResults = 1;
-	}
-
-	/**
-	 * Gets the ADQL object associated with this node.
-	 * It may be a matched ADQL item (it depends of what returns the {@link SearchResult#isResult() isResult()} function).
-	 * 
-	 * @return	The node value.
-	 */
-	public final ADQLObject getResult(){
-		return value;
-	}
-
-	/**
-	 * Indicates whether the ADQL object (returned by {@link SearchResult#getResult() getResult()}) is a match or not.
-	 * 
-	 * @return	<i>true</i> if this SearchResult corresponds to a matched ADQL item, <i>false</i> otherwise.
-	 */
-	public final boolean isResult(){
-		return result;
-	}
-
-	/**
-	 * Gets the error that occurs when replacing the matched item.
-	 * 
-	 * @return	Replacing error.
-	 */
-	public final String getError(){
-		return error;
-	}
-
-	/**
-	 * Indicates whether there was an error during the replacement of the matched item.
-	 * 
-	 * @return	<i>true</i> if there was an error during the replacement, <i>false</i> else.
-	 */
-	public final boolean hasError(){
-		return error != null;
-	}
-
-	/**
-	 * Sets the explanation of why the matched item has not been replaced.
-	 * 
-	 * @param msg	Error description.
-	 */
-	public final void setError(String msg){
-		if (msg != null){
-			msg = msg.trim();
-			error = (msg.length() == 0) ? null : msg;
-		}else
-			error = null;
-	}
-
-	/**
-	 * Gets the parent node.
-	 * 
-	 * @return	Its parent node.
-	 */
-	public final SearchResult getParent(){
-		return parent;
-	}
-
-	/**
-	 * Changes the parent node.
-	 * 
-	 * @param newParent	Its new parent node.
-	 */
-	private final void setParent(SearchResult newParent){
-		parent = newParent;
-	}
-
-	/**
-	 * Gets an iterator on the children list of this SearchResult.
-	 * 
-	 * @return	An iterator on its children.
-	 */
-	public final Iterator<SearchResult> getChildren(){
-		return children.iterator();
-	}
-
-	/**
-	 * Indicates whether this node is a leaf (that is to say if it has children).
-	 * 
-	 * @return	<i>true</i> if this node is a leaf, <i>false</i> otherwise.
-	 */
-	public final boolean isLeaf(){
-		return children.isEmpty();
-	}
-
-	/**
-	 * Lets adding a child to this node.
-	 * 
-	 * @param result	The SearchResult to add.
-	 */
-	public final void add(SearchResult result){
-		if (result != null){
-			// Add the given result:
-			children.add(result);
-
-			// Set its parent:
-			result.setParent(this);
-
-			// Update the total number of results from this node:
-			updateNbResults();
-		}
-	}
-
-	/**
-	 * Counts exactly the total number of results from this node (included).
-	 * Once the counting phase finished the direct parent node is notify that it must update its own number of results.
-	 */
-	private final void updateNbResults(){
-		synchronized(this){
-			// Count all results from this node:
-			nbResults = isResult() ? 1 : 0;
-			for(SearchResult r : children)
-				nbResults += r.getNbResults();
-		}
-
-		// Notify the direct parent node:
-		if (parent != null)
-			parent.updateNbResults();
-	}
-
-	/**
-	 * <p>Indicates whether this node is and/or contains some results (SearchResult objects whose the function isResult() returns <i>true</i>).</p>
-	 * 
-	 * @return	<i>true</i> if this SearchResult is a result or if one of its children is a result, <i>false</i> otherwise.
-	 */
-	public final boolean hasResult(){
-		return nbResults > 0;
-	}
-
-	/**
-	 * <p>Tells exactly the number of SearchResult which are really results.</p>
-	 * 
-	 * @return	The number of matched ADQL item.
-	 */
-	public final int getNbResults(){
-		return nbResults;
-	}
-
-	/**
-	 * Lets iterating on all contained SearchResult objects (itself included) which are really a result (whose the function isResult() returns <i>true</i>).
-	 * 
-	 * @see java.lang.Iterable#iterator()
-	 * @see SearchIterator
-	 */
-	public final Iterator<SearchResult> iterator(){
-		return new SearchIterator(this);
-	}
-
-}
diff --git a/test/adql/TestADQLQuery.java b/test/adql/TestADQLQuery.java
index 7fac283d388e9b9db1e92921d3667455e912389a..54a704ecdef9a2759b37aaee65df4207f34bb3b2 100644
--- a/test/adql/TestADQLQuery.java
+++ b/test/adql/TestADQLQuery.java
@@ -1,6 +1,13 @@
 package adql;
 
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
 
 import adql.query.ADQLObject;
 import adql.query.ADQLOrder;
@@ -9,13 +16,10 @@ import adql.query.ClauseADQL;
 import adql.query.ClauseConstraints;
 import adql.query.ClauseSelect;
 import adql.query.SelectItem;
-
 import adql.query.constraint.Comparison;
 import adql.query.constraint.ComparisonOperator;
 import adql.query.constraint.ConstraintsGroup;
-
 import adql.query.from.ADQLTable;
-
 import adql.query.operand.ADQLColumn;
 import adql.query.operand.Concatenation;
 import adql.query.operand.NumericConstant;
@@ -23,24 +27,45 @@ import adql.query.operand.Operation;
 import adql.query.operand.OperationType;
 import adql.query.operand.StringConstant;
 import adql.query.operand.WrappedOperand;
-
+import adql.search.IReplaceHandler;
 import adql.search.ISearchHandler;
 import adql.search.SearchColumnHandler;
+import adql.search.SimpleReplaceHandler;
 
 public class TestADQLQuery {
-	public static final void main(String[] args) throws Exception{
-		ADQLQuery query = new ADQLQuery();
+	private ADQLQuery query = null;
+	private List<ADQLColumn> columns = new ArrayList<ADQLColumn>(8);
+	private List<ADQLColumn> typeObjColumns = new ArrayList<ADQLColumn>(3);
+
+	@Before
+	public void setUp(){
+		query = new ADQLQuery();
+		columns.clear();
+		typeObjColumns.clear();
+
+		columns.add(new ADQLColumn("O", "nameObj")); // 0 = O.nameObj
+		columns.add(new ADQLColumn("O", "typeObj")); // 1 = O.typeObj
+		columns.add(new ADQLColumn("O", "ra"));      // 2 = O.ra
+		columns.add(new ADQLColumn("O", "dec"));     // 3 = O.dec
+		columns.add(new ADQLColumn("ra"));           // 4 = ra
+		columns.add(new ADQLColumn("dec"));          // 5 = dec
+		columns.add(new ADQLColumn("typeObj"));      // 6 = typeObj
+		columns.add(new ADQLColumn("typeObj"));      // 7 = typeObj
+
+		typeObjColumns.add(columns.get(1));
+		typeObjColumns.add(columns.get(6));
+		typeObjColumns.add(columns.get(7));
 
 		// SELECT:
 		ClauseSelect select = query.getSelect();
 		Concatenation concatObj = new Concatenation();
-		concatObj.add(new ADQLColumn("O", "nameObj"));
+		concatObj.add(columns.get(0)); // O.nameObj
 		concatObj.add(new StringConstant(" ("));
-		concatObj.add(new ADQLColumn("O", "typeObj"));
+		concatObj.add(columns.get(1)); // O.typeObj
 		concatObj.add(new StringConstant(")"));
 		select.add(new SelectItem(new WrappedOperand(concatObj), "Nom objet"));
-		select.add(new ADQLColumn("O", "ra"));
-		select.add(new ADQLColumn("O", "dec"));
+		select.add(columns.get(2)); // O.ra
+		select.add(columns.get(3)); // O.dec
 
 		// FROM:
 		ADQLTable table = new ADQLTable("truc.ObsCore");
@@ -50,40 +75,53 @@ public class TestADQLQuery {
 
 		// WHERE:
 		ClauseConstraints where = query.getWhere();
-		where.add(new Comparison(new Operation(new ADQLColumn("ra"), OperationType.DIV, new ADQLColumn("dec")), ComparisonOperator.GREATER_THAN, new NumericConstant("1")));
+		// ra/dec > 1
+		where.add(new Comparison(new Operation(columns.get(4), OperationType.DIV, columns.get(5)), ComparisonOperator.GREATER_THAN, new NumericConstant("1")));
 		ConstraintsGroup constOr = new ConstraintsGroup();
-		constOr.add(new Comparison(new ADQLColumn("typeObj"), ComparisonOperator.EQUAL, new StringConstant("Star")));
-		constOr.add("OR", new Comparison(new ADQLColumn("typeObj"), ComparisonOperator.LIKE, new StringConstant("Galaxy*")));
+		// AND (typeObj == 'Star'
+		constOr.add(new Comparison(columns.get(6), ComparisonOperator.EQUAL, new StringConstant("Star")));
+		// OR typeObj LIKE 'Galaxy*')
+		constOr.add("OR", new Comparison(columns.get(7), ComparisonOperator.LIKE, new StringConstant("Galaxy*")));
 		where.add("AND", constOr);
 
 		// ORDER BY:
 		ClauseADQL<ADQLOrder> orderBy = query.getOrderBy();
 		orderBy.add(new ADQLOrder(1, true));
+	}
 
-		System.out.println("*** QUERY ***\n" + query.toADQL());
+	@Test
+	public void testADQLQuery(){
+		assertEquals("SELECT (O.nameObj || ' (' || O.typeObj || ')') AS Nom objet , O.ra , O.dec\nFROM truc.ObsCore AS O\nWHERE ra/dec > 1 AND (typeObj = 'Star' OR typeObj LIKE 'Galaxy*')\nORDER BY 1 DESC", query.toADQL());
+	}
 
+	@Test
+	public void testSearch(){
 		ISearchHandler sHandler = new SearchColumnHandler(false);
 		Iterator<ADQLObject> results = query.search(sHandler);
-		//		IReplaceHandler sHandler = new SimpleReplaceHandler(false, false) {
-		//
-		//			@Override
-		//			protected boolean match(ADQLObject obj) {
-		//				return (obj instanceof ADQLColumn) && (((ADQLColumn)obj).getColumnName().equalsIgnoreCase("typeObj"));
-		//			}
-		//
-		//			@Override
-		//			public ADQLObject getReplacer(ADQLObject objToReplace) throws UnsupportedOperationException {
-		//				return new ADQLColumn("NewTypeObj");
-		//			}
-		//
-		//		};
-		//		sHandler.searchAndReplace(query);
-		//		System.out.println("INFO: "+sHandler.getNbReplacement()+"/"+sHandler.getNbMatch()+" replaced objects !");
-		//		Iterator<ADQLObject> results = sHandler.iterator();
-		System.out.println("\n*** SEARCH ALL COLUMNS ***");
-		while(results.hasNext())
-			System.out.println("\t- " + results.next().toADQL());
-
-		System.out.println("\n*** QUERY ***\n" + query.toADQL());
+		assertEquals(columns.size(), sHandler.getNbMatch());
+		for(ADQLColumn expectedCol : columns)
+			assertEquals(expectedCol, results.next());
+	}
+
+	@Test
+	public void testReplace(){
+		IReplaceHandler sHandler = new SimpleReplaceHandler(false, false){
+			@Override
+			protected boolean match(ADQLObject obj){
+				return (obj instanceof ADQLColumn) && (((ADQLColumn)obj).getColumnName().equalsIgnoreCase("typeObj"));
+			}
+
+			@Override
+			public ADQLObject getReplacer(ADQLObject objToReplace) throws UnsupportedOperationException{
+				return new ADQLColumn("NewTypeObj");
+			}
+		};
+		sHandler.searchAndReplace(query);
+		assertEquals(typeObjColumns.size(), sHandler.getNbMatch());
+		assertEquals(sHandler.getNbMatch(), sHandler.getNbReplacement());
+		Iterator<ADQLObject> results = sHandler.iterator();
+		for(ADQLColumn expectedCol : typeObjColumns)
+			assertEquals(expectedCol, results.next());
+		assertEquals("SELECT (O.nameObj || ' (' || NewTypeObj || ')') AS Nom objet , O.ra , O.dec\nFROM truc.ObsCore AS O\nWHERE ra/dec > 1 AND (NewTypeObj = 'Star' OR NewTypeObj LIKE 'Galaxy*')\nORDER BY 1 DESC", query.toADQL());
 	}
 }
diff --git a/test/adql/TestIN.java b/test/adql/TestIN.java
index 43ad6cac396f2260a8ff0af7e44803ce67aa2936..d3ad2f2241ff9544aa287aa333d21053623ce294 100644
--- a/test/adql/TestIN.java
+++ b/test/adql/TestIN.java
@@ -1,32 +1,52 @@
 package adql;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
 import java.util.Iterator;
 
+import org.junit.BeforeClass;
+import org.junit.Test;
+
 import adql.query.ADQLList;
 import adql.query.ADQLObject;
 import adql.query.ADQLOrder;
 import adql.query.ADQLQuery;
 import adql.query.ClauseSelect;
-
 import adql.query.constraint.In;
-
 import adql.query.from.ADQLTable;
-
 import adql.query.operand.ADQLColumn;
 import adql.query.operand.ADQLOperand;
 import adql.query.operand.StringConstant;
-
 import adql.search.IReplaceHandler;
 import adql.search.SimpleReplaceHandler;
-
+import adql.translator.ADQLTranslator;
 import adql.translator.PostgreSQLTranslator;
 
 public class TestIN {
 
-	public static void main(String[] args) throws Exception{
-		In myIn = new In(new ADQLColumn("typeObj"), new ADQLOperand[]{new StringConstant("galaxy"),new StringConstant("star"),new StringConstant("planet"),new StringConstant("nebula")}, true);
-		System.out.println(myIn.getName() + ": " + myIn.toADQL());
+	private static ADQLTranslator translator = null;
+
+	@BeforeClass
+	public static void setUpBeforeClass(){
+		translator = new PostgreSQLTranslator();
+	}
 
+	@Test
+	public void testIN(){
+		// Test with a simple list of values (here, string constants):
+		In myIn = new In(new ADQLColumn("typeObj"), new ADQLOperand[]{new StringConstant("galaxy"),new StringConstant("star"),new StringConstant("planet"),new StringConstant("nebula")}, true);
+		// check the ADQL:
+		assertEquals("typeObj NOT IN ('galaxy' , 'star' , 'planet' , 'nebula')", myIn.toADQL());
+		// check the SQL translation:
+		try{
+			assertEquals(myIn.toADQL(), translator.translate(myIn));
+		}catch(Exception ex){
+			ex.printStackTrace();
+			fail("This test should have succeeded because the IN statement is correct and theoretically well supported by the POSTGRESQL translator!");
+		}
+
+		// Test with a sub-query:
 		ADQLQuery subQuery = new ADQLQuery();
 
 		ClauseSelect select = subQuery.getSelect();
@@ -40,10 +60,17 @@ public class TestIN {
 		orderBy.add(new ADQLOrder(1));
 
 		myIn.setSubQuery(subQuery);
-		System.out.println("\n*** " + myIn.getName().toUpperCase() + " ***\n" + myIn.toADQL());
-		PostgreSQLTranslator translator = new PostgreSQLTranslator();
-		System.out.println("\n*** SQL TRANSLATION ***\n" + translator.translate(myIn));
-
+		// check the ADQL:
+		assertEquals("typeObj NOT IN (SELECT DISTINCT TOP 10 typeObj\nFROM Objects\nORDER BY 1 ASC)", myIn.toADQL());
+		// check the SQL translation:
+		try{
+			assertEquals("typeObj NOT IN (SELECT DISTINCT typeObj AS \"typeObj\"\nFROM Objects\nORDER BY 1 ASC\nLimit 10)", translator.translate(myIn));
+		}catch(Exception ex){
+			ex.printStackTrace();
+			fail("This test should have succeeded because the IN statement is correct and theoretically well supported by the POSTGRESQL translator!");
+		}
+
+		// Test after replacement inside this IN statement:
 		IReplaceHandler sHandler = new SimpleReplaceHandler(true){
 
 			@Override
@@ -57,13 +84,12 @@ public class TestIN {
 			}
 		};
 		sHandler.searchAndReplace(myIn);
-		System.out.println("INFO: " + sHandler.getNbReplacement() + "/" + sHandler.getNbMatch() + " replaced objects !");
+		assertEquals(2, sHandler.getNbMatch());
+		assertEquals(sHandler.getNbMatch(), sHandler.getNbReplacement());
 		Iterator<ADQLObject> results = sHandler.iterator();
-		System.out.println("\n*** SEARCH RESULTS ***");
 		while(results.hasNext())
-			System.out.println("\t- " + results.next());
-
-		System.out.println("\n*** AFTER REPLACEMENT ***\n" + myIn.toADQL());
+			assertEquals("typeObj", results.next().toADQL());
+		assertEquals("type NOT IN (SELECT DISTINCT TOP 10 type\nFROM Objects\nORDER BY 1 ASC)", myIn.toADQL());
 	}
 
 }
diff --git a/test/adql/IdentifierFieldTest.java b/test/adql/TestIdentifierField.java
similarity index 93%
rename from test/adql/IdentifierFieldTest.java
rename to test/adql/TestIdentifierField.java
index 8caecebf097c4e7b4c2ee4920307d92200cefa8d..c4c5fc2dc99d3d79927e0f2a6e488753a0f1004b 100644
--- a/test/adql/IdentifierFieldTest.java
+++ b/test/adql/TestIdentifierField.java
@@ -7,7 +7,7 @@ import org.junit.Test;
 
 import adql.query.IdentifierField;
 
-public class IdentifierFieldTest {
+public class TestIdentifierField {
 
 	@Test
 	public void testIsCaseSensitive(){
diff --git a/test/adql/query/from/TestCrossJoin.java b/test/adql/query/from/TestCrossJoin.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce440bcb13f3dc44ef1032182a4c5c50c9fd236a
--- /dev/null
+++ b/test/adql/query/from/TestCrossJoin.java
@@ -0,0 +1,95 @@
+package adql.query.from;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+import adql.db.DBColumn;
+import adql.db.DBType;
+import adql.db.DBType.DBDatatype;
+import adql.db.DefaultDBColumn;
+import adql.db.DefaultDBTable;
+import adql.db.SearchColumnList;
+import adql.query.IdentifierField;
+
+public class TestCrossJoin {
+
+	private ADQLTable tableA, tableB;
+
+	@AfterClass
+	public static void tearDownAfterClass() throws Exception{}
+
+	@Before
+	public void setUp() throws Exception{
+		/* SET THE TABLES AND COLUMNS NEEDED FOR THE TEST */
+		// Describe the available table:
+		DefaultDBTable metaTableA = new DefaultDBTable("A");
+		metaTableA.setADQLSchemaName("public");
+		DefaultDBTable metaTableB = new DefaultDBTable("B");
+		metaTableB.setADQLSchemaName("public");
+
+		// Describe its columns:
+		metaTableA.addColumn(new DefaultDBColumn("id", new DBType(DBDatatype.VARCHAR), metaTableA));
+		metaTableA.addColumn(new DefaultDBColumn("txta", new DBType(DBDatatype.VARCHAR), metaTableA));
+		metaTableB.addColumn(new DefaultDBColumn("id", new DBType(DBDatatype.VARCHAR), metaTableB));
+		metaTableB.addColumn(new DefaultDBColumn("txtb", new DBType(DBDatatype.VARCHAR), metaTableB));
+
+		// Build the ADQL tables:
+		tableA = new ADQLTable("A");
+		tableA.setDBLink(metaTableA);
+		tableB = new ADQLTable("B");
+		tableB.setDBLink(metaTableB);
+	}
+
+	@Test
+	public void testGetDBColumns(){
+		try{
+			ADQLJoin join = new CrossJoin(tableA, tableB);
+			SearchColumnList joinColumns = join.getDBColumns();
+			assertEquals(4, joinColumns.size());
+
+			// check column A.id and B.id
+			List<DBColumn> lstFound = joinColumns.search(null, null, null, "id", IdentifierField.getFullCaseSensitive(true));
+			assertEquals(2, lstFound.size());
+			// A.id
+			assertNotNull(lstFound.get(0).getTable());
+			assertEquals("A", lstFound.get(0).getTable().getADQLName());
+			assertEquals("public", lstFound.get(0).getTable().getADQLSchemaName());
+			assertEquals(1, joinColumns.search(null, "public", "A", "id", IdentifierField.getFullCaseSensitive(true)).size());
+			// B.id
+			assertNotNull(lstFound.get(1).getTable());
+			assertEquals("B", lstFound.get(1).getTable().getADQLName());
+			assertEquals("public", lstFound.get(1).getTable().getADQLSchemaName());
+			assertEquals(1, joinColumns.search(null, "public", "B", "id", IdentifierField.getFullCaseSensitive(true)).size());
+			assertEquals(0, joinColumns.search(null, "public", "C", "id", IdentifierField.getFullCaseSensitive(true)).size());
+
+			// check column A.txta
+			lstFound = joinColumns.search(null, null, null, "txta", IdentifierField.getFullCaseSensitive(true));
+			assertEquals(1, lstFound.size());
+			assertNotNull(lstFound.get(0).getTable());
+			assertEquals("A", lstFound.get(0).getTable().getADQLName());
+			assertEquals("public", lstFound.get(0).getTable().getADQLSchemaName());
+			assertEquals(1, joinColumns.search(null, "public", "A", "txta", IdentifierField.getFullCaseSensitive(true)).size());
+			assertEquals(0, joinColumns.search(null, "public", "B", "txta", IdentifierField.getFullCaseSensitive(true)).size());
+
+			// check column B.txtb
+			lstFound = joinColumns.search(null, null, null, "txtb", IdentifierField.getFullCaseSensitive(true));
+			assertEquals(1, lstFound.size());
+			assertNotNull(lstFound.get(0).getTable());
+			assertEquals("B", lstFound.get(0).getTable().getADQLName());
+			assertEquals("public", lstFound.get(0).getTable().getADQLSchemaName());
+			assertEquals(1, joinColumns.search(null, "public", "B", "txtb", IdentifierField.getFullCaseSensitive(true)).size());
+			assertEquals(0, joinColumns.search(null, "public", "A", "txtb", IdentifierField.getFullCaseSensitive(true)).size());
+
+		}catch(Exception ex){
+			ex.printStackTrace();
+			fail("This test should have succeeded!");
+		}
+	}
+}
diff --git a/test/adql/query/from/TestInnerJoin.java b/test/adql/query/from/TestInnerJoin.java
new file mode 100644
index 0000000000000000000000000000000000000000..57c4f87edaf197d4a3df74b1925dd4c542735347
--- /dev/null
+++ b/test/adql/query/from/TestInnerJoin.java
@@ -0,0 +1,158 @@
+package adql.query.from;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import adql.db.DBColumn;
+import adql.db.DBCommonColumn;
+import adql.db.DBType;
+import adql.db.DBType.DBDatatype;
+import adql.db.DefaultDBColumn;
+import adql.db.DefaultDBTable;
+import adql.db.SearchColumnList;
+import adql.query.IdentifierField;
+import adql.query.operand.ADQLColumn;
+
+public class TestInnerJoin {
+
+	private ADQLTable tableA, tableB, tableC;
+
+	@Before
+	public void setUp() throws Exception{
+		/* SET THE TABLES AND COLUMNS NEEDED FOR THE TEST */
+		// Describe the available table:
+		DefaultDBTable metaTableA = new DefaultDBTable("A");
+		metaTableA.setADQLSchemaName("public");
+		DefaultDBTable metaTableB = new DefaultDBTable("B");
+		metaTableB.setADQLSchemaName("public");
+		DefaultDBTable metaTableC = new DefaultDBTable("C");
+		metaTableC.setADQLSchemaName("public");
+
+		// Describe its columns:
+		metaTableA.addColumn(new DefaultDBColumn("id", new DBType(DBDatatype.VARCHAR), metaTableA));
+		metaTableA.addColumn(new DefaultDBColumn("txta", new DBType(DBDatatype.VARCHAR), metaTableA));
+		metaTableB.addColumn(new DefaultDBColumn("id", new DBType(DBDatatype.VARCHAR), metaTableB));
+		metaTableB.addColumn(new DefaultDBColumn("txtb", new DBType(DBDatatype.VARCHAR), metaTableB));
+		metaTableC.addColumn(new DefaultDBColumn("Id", new DBType(DBDatatype.VARCHAR), metaTableC));
+		metaTableC.addColumn(new DefaultDBColumn("txta", new DBType(DBDatatype.VARCHAR), metaTableC));
+		metaTableC.addColumn(new DefaultDBColumn("txtc", new DBType(DBDatatype.VARCHAR), metaTableC));
+
+		// Build the ADQL tables:
+		tableA = new ADQLTable("A");
+		tableA.setDBLink(metaTableA);
+		tableB = new ADQLTable("B");
+		tableB.setDBLink(metaTableB);
+		tableC = new ADQLTable("C");
+		tableC.setDBLink(metaTableC);
+	}
+
+	@Test
+	public void testGetDBColumns(){
+		// Test NATURAL JOIN 1:
+		try{
+			ADQLJoin join = new InnerJoin(tableA, tableB);
+			SearchColumnList joinColumns = join.getDBColumns();
+			assertEquals(3, joinColumns.size());
+			List<DBColumn> lstFound = joinColumns.search(null, null, null, "id", IdentifierField.getFullCaseSensitive(true));
+			assertEquals(1, lstFound.size());
+			assertEquals(DBCommonColumn.class, lstFound.get(0).getClass());
+			assertEquals(1, joinColumns.search(null, "public", "A", "id", IdentifierField.getFullCaseSensitive(true)).size());
+			assertEquals(1, joinColumns.search(null, "public", "B", "id", IdentifierField.getFullCaseSensitive(true)).size());
+			assertEquals(0, joinColumns.search(null, "public", "C", "id", IdentifierField.getFullCaseSensitive(true)).size());
+			lstFound = joinColumns.search(null, "public", "A", "txta", IdentifierField.getFullCaseSensitive(true));
+			assertEquals(1, lstFound.size());
+			lstFound = joinColumns.search(null, "public", "B", "txtb", IdentifierField.getFullCaseSensitive(true));
+			assertEquals(1, lstFound.size());
+		}catch(Exception ex){
+			ex.printStackTrace();
+			fail("This test should have succeeded!");
+		}
+
+		// Test NATURAL JOIN 2:
+		try{
+			ADQLJoin join = new InnerJoin(tableA, tableC);
+			SearchColumnList joinColumns = join.getDBColumns();
+			assertEquals(3, joinColumns.size());
+
+			// check id (column common to table A and C only):
+			List<DBColumn> lstFound = joinColumns.search(null, null, null, "id", IdentifierField.getFullCaseSensitive(true));
+			assertEquals(1, lstFound.size());
+			assertEquals(DBCommonColumn.class, lstFound.get(0).getClass());
+			assertEquals(1, joinColumns.search(null, "public", "A", "id", IdentifierField.getFullCaseSensitive(true)).size());
+			assertEquals(1, joinColumns.search(null, "public", "C", "id", IdentifierField.getFullCaseSensitive(true)).size());
+			assertEquals(0, joinColumns.search(null, "public", "B", "id", IdentifierField.getFullCaseSensitive(true)).size());
+
+			// check txta (column common to table A and C only):
+			lstFound = joinColumns.search(null, null, null, "txta", IdentifierField.getFullCaseSensitive(true));
+			assertEquals(1, lstFound.size());
+			assertEquals(DBCommonColumn.class, lstFound.get(0).getClass());
+			assertEquals(1, joinColumns.search(null, "public", "A", "txta", IdentifierField.getFullCaseSensitive(true)).size());
+			assertEquals(1, joinColumns.search(null, "public", "C", "txta", IdentifierField.getFullCaseSensitive(true)).size());
+			assertEquals(0, joinColumns.search(null, "public", "B", "id", IdentifierField.getFullCaseSensitive(true)).size());
+
+			// check txtc (only for table C)
+			lstFound = joinColumns.search(null, null, null, "txtc", IdentifierField.getFullCaseSensitive(true));
+			assertEquals(1, lstFound.size());
+			assertNotNull(lstFound.get(0).getTable());
+			assertEquals("C", lstFound.get(0).getTable().getADQLName());
+			assertEquals("public", lstFound.get(0).getTable().getADQLSchemaName());
+
+		}catch(Exception ex){
+			ex.printStackTrace();
+			fail("This test should have succeeded!");
+		}
+
+		// Test with a USING("id"):
+		try{
+			List<ADQLColumn> usingList = new ArrayList<ADQLColumn>(1);
+			usingList.add(new ADQLColumn("id"));
+			ADQLJoin join = new InnerJoin(tableA, tableC, usingList);
+			SearchColumnList joinColumns = join.getDBColumns();
+			assertEquals(4, joinColumns.size());
+
+			// check id (column common to table A and C only):
+			List<DBColumn> lstFound = joinColumns.search(null, null, null, "id", IdentifierField.getFullCaseSensitive(true));
+			assertEquals(1, lstFound.size());
+			assertEquals(DBCommonColumn.class, lstFound.get(0).getClass());
+			assertEquals(1, joinColumns.search(null, "public", "A", "id", IdentifierField.getFullCaseSensitive(true)).size());
+			assertEquals(1, joinColumns.search(null, "public", "C", "id", IdentifierField.getFullCaseSensitive(true)).size());
+			assertEquals(0, joinColumns.search(null, "public", "B", "id", IdentifierField.getFullCaseSensitive(true)).size());
+
+			// check A.txta and C.txta:
+			lstFound = joinColumns.search(null, null, null, "txta", IdentifierField.getFullCaseSensitive(true));
+			assertEquals(2, lstFound.size());
+			// A.txta
+			assertNotNull(lstFound.get(0).getTable());
+			assertEquals("A", lstFound.get(0).getTable().getADQLName());
+			assertEquals("public", lstFound.get(0).getTable().getADQLSchemaName());
+			assertEquals(1, joinColumns.search(null, "public", "A", "txta", IdentifierField.getFullCaseSensitive(true)).size());
+			// C.txta
+			assertNotNull(lstFound.get(1).getTable());
+			assertEquals("C", lstFound.get(1).getTable().getADQLName());
+			assertEquals("public", lstFound.get(1).getTable().getADQLSchemaName());
+			assertEquals(1, joinColumns.search(null, "public", "C", "txta", IdentifierField.getFullCaseSensitive(true)).size());
+			assertEquals(0, joinColumns.search(null, "public", "B", "txta", IdentifierField.getFullCaseSensitive(true)).size());
+
+			// check txtc (only for table C):
+			lstFound = joinColumns.search(null, null, null, "txtc", IdentifierField.getFullCaseSensitive(true));
+			assertEquals(1, lstFound.size());
+			assertNotNull(lstFound.get(0).getTable());
+			assertEquals("C", lstFound.get(0).getTable().getADQLName());
+			assertEquals("public", lstFound.get(0).getTable().getADQLSchemaName());
+			assertEquals(1, joinColumns.search(null, "public", "C", "txtc", IdentifierField.getFullCaseSensitive(true)).size());
+			assertEquals(0, joinColumns.search(null, "public", "A", "txtc", IdentifierField.getFullCaseSensitive(true)).size());
+
+		}catch(Exception ex){
+			ex.printStackTrace();
+			fail("This test should have succeeded!");
+		}
+	}
+
+}
diff --git a/test/tap/config/AllTests.java b/test/tap/config/AllTAPConfigTests.java
similarity index 96%
rename from test/tap/config/AllTests.java
rename to test/tap/config/AllTAPConfigTests.java
index 159963e3fbc7801273299061297e25b07dbba75e..c752a887f6f0a88877e813e8a685619bc7cca507 100644
--- a/test/tap/config/AllTests.java
+++ b/test/tap/config/AllTAPConfigTests.java
@@ -10,7 +10,7 @@ import tap.parameters.TestMaxRecController;
 
 @RunWith(Suite.class)
 @SuiteClasses({TestTAPConfiguration.class,TestConfigurableServiceConnection.class,TestConfigurableTAPFactory.class,TestMaxRecController.class})
-public class AllTests {
+public class AllTAPConfigTests {
 
 	public final static Properties getValidProperties(){
 		Properties validProp = new Properties();
diff --git a/test/tap/config/TestConfigurableServiceConnection.java b/test/tap/config/TestConfigurableServiceConnection.java
index d232be86d0ed854a6923f8257bb6ff31fc584588..07797025736c6a334e19528c59e38435ce417d60 100644
--- a/test/tap/config/TestConfigurableServiceConnection.java
+++ b/test/tap/config/TestConfigurableServiceConnection.java
@@ -95,7 +95,7 @@ public class TestConfigurableServiceConnection {
 	@BeforeClass
 	public static void setUp() throws Exception{
 		// LOAD ALL PROPERTIES FILES NEEDED FOR ALL THE TESTS:
-		validProp = AllTests.getValidProperties();
+		validProp = AllTAPConfigTests.getValidProperties();
 
 		noFmProp = (Properties)validProp.clone();
 		noFmProp.setProperty(KEY_FILE_MANAGER, "");
diff --git a/test/tap/config/TestConfigurableTAPFactory.java b/test/tap/config/TestConfigurableTAPFactory.java
index f270ad1394c4cebc5e5c9d2937cbcfb163b8357f..e4c8e38f0cf37b434a869036ba8d338d09c65819 100644
--- a/test/tap/config/TestConfigurableTAPFactory.java
+++ b/test/tap/config/TestConfigurableTAPFactory.java
@@ -83,7 +83,7 @@ public class TestConfigurableTAPFactory {
 		serviceConnection = new ServiceConnectionTest();
 
 		// LOAD ALL PROPERTIES FILES NEEDED FOR ALL THE TESTS:
-		validJDBCProp = AllTests.getValidProperties();
+		validJDBCProp = AllTAPConfigTests.getValidProperties();
 
 		setJNDIDatasource();
 		validJNDIProp = (Properties)validJDBCProp.clone();
diff --git a/test/uws/TestISO8601Format.java b/test/uws/TestISO8601Format.java
index b397c85fa4895236ee176a44137f5bb1736c2a03..22c9ee920c8fd0585a9dae1b0df7a7db60cbced5 100644
--- a/test/uws/TestISO8601Format.java
+++ b/test/uws/TestISO8601Format.java
@@ -14,7 +14,7 @@ import org.junit.Test;
 public class TestISO8601Format {
 
 	private final long date = 1411737870325L;		// Fri Sep 26 15:24:30 CEST 2014 = 2014-09-26T15:24:30.325+02:00 = 1411737870325 ms
-	private final long dateAlone = 1411682400000L;
+	private final long dateAlone = 1411689600000L;
 
 	private final long oldDate = -3506029200000L;	// Thu Nov 25 00:00:00 CET 1858 = 1858-11-25T00:00:00+01:00 = -3506029200000 ms
 
@@ -125,8 +125,8 @@ public class TestISO8601Format {
 			assertEquals(date - 325, ISO8601Format.parse("2014-09-26T13:24:30Z"));
 
 			// If no time zone is specified, the local one should be used:
-			assertEquals(date, ISO8601Format.parse("2014-09-26T15:24:30.325"));
-			assertEquals(date - 325, ISO8601Format.parse("2014-09-26T15:24:30"));
+			assertEquals(date, ISO8601Format.parse("2014-09-26T13:24:30.325"));
+			assertEquals(date - 325, ISO8601Format.parse("2014-09-26T13:24:30"));
 
 			// All the previous tests without the _ between days, month, and years:
 			assertEquals(0, ISO8601Format.parse("19700101T01:00:00+01:00"));
@@ -138,8 +138,8 @@ public class TestISO8601Format {
 			assertEquals(date - 325, ISO8601Format.parse("20140926T15:24:30+02:00"));
 			assertEquals(date, ISO8601Format.parse("20140926T13:24:30.325Z"));
 			assertEquals(date - 325, ISO8601Format.parse("20140926T13:24:30Z"));
-			assertEquals(date, ISO8601Format.parse("20140926T15:24:30.325"));
-			assertEquals(date - 325, ISO8601Format.parse("20140926T15:24:30"));
+			assertEquals(date, ISO8601Format.parse("20140926T13:24:30.325"));
+			assertEquals(date - 325, ISO8601Format.parse("20140926T13:24:30"));
 
 			// All the previous tests without the : between hours, minutes and seconds:
 			assertEquals(0, ISO8601Format.parse("1970-01-01T010000+0100"));
@@ -152,8 +152,8 @@ public class TestISO8601Format {
 			assertEquals(oldDate, ISO8601Format.parse("1858-11-24 23:00:00Z"));
 			assertEquals(date, ISO8601Format.parse("2014-09-26 13:24:30.325Z"));
 			assertEquals(date - 325, ISO8601Format.parse("2014-09-26 13:24:30Z"));
-			assertEquals(date, ISO8601Format.parse("2014-09-26 15:24:30.325"));
-			assertEquals(date - 325, ISO8601Format.parse("2014-09-26 15:24:30"));
+			assertEquals(date, ISO8601Format.parse("2014-09-26 13:24:30.325"));
+			assertEquals(date - 325, ISO8601Format.parse("2014-09-26 13:24:30"));
 
 		}catch(ParseException ex){
 			ex.printStackTrace(System.err);
diff --git a/test/uws/service/file/TestLogRotation.java b/test/uws/service/file/TestLogRotation.java
index b721d00fea953f9f04689a89172657ab2c7e1f58..16aa1e499f3ab6d9758b4a307130f89ba2869538 100644
--- a/test/uws/service/file/TestLogRotation.java
+++ b/test/uws/service/file/TestLogRotation.java
@@ -4,12 +4,13 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.fail;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStreamReader;
 
 import org.junit.Test;
 
-import uws.UWSException;
 import uws.service.log.DefaultUWSLog;
 import uws.service.log.UWSLog;
 import uws.service.log.UWSLog.LogLevel;
@@ -219,18 +220,27 @@ public class TestLogRotation {
 		try{
 			final LocalUWSFileManager fileManager = new LocalUWSFileManager(new File("."));
 			fileManager.logRotation = new EventFrequency("m");
+			final int MAX_TIME = 3000; // 3 seconds => 68 messages (for 5 threads)
+			int nbExpectedMessages = 0;
 
+			// Delete old log file:
+			fileManager.getLogFile(LogLevel.DEBUG, null).delete();
+
+			// Log a lot of messages:
 			final UWSLog logger = new DefaultUWSLog(fileManager);
 			for(int i = 0; i < 5; i++){
 				final int logFreq = i + 1;
+				nbExpectedMessages += 30 / logFreq;
 				(new Thread(new Runnable(){
 					@Override
 					public void run(){
 						try{
-							for(int cnt = 0; cnt < 3 * 60 / logFreq; cnt++){
+							final int nbMsgs = 30 / logFreq;
+							final int freq = MAX_TIME / nbMsgs;
+							for(int cnt = 0; cnt < nbMsgs; cnt++){
 								logger.log(LogLevel.INFO, "TEST", "LOG MESSAGE FROM Thread-" + logFreq, null);
 								assertFalse(fileManager.getLogOutput(LogLevel.INFO, "UWS").checkError());	// if true, it means that at least one attempt to write something fails, and so, that write attempts have been done after a log rotation!
-								Thread.sleep(1000 * logFreq);
+								Thread.sleep(freq);
 							}
 						}catch(InterruptedException e){
 							e.printStackTrace(System.err);
@@ -242,14 +252,25 @@ public class TestLogRotation {
 					}
 				})).start();
 			}
-			Thread.sleep(180000);
+			Thread.sleep(MAX_TIME);
+
+			// Check that all messages have been well written:
+			BufferedReader input = new BufferedReader(new InputStreamReader(fileManager.getLogInput(LogLevel.DEBUG, null)));
+			int nbLines = 0;
+			while(input.readLine() != null)
+				nbLines++;
+			nbLines -= 3; // deduce the number of 3 header lines
+			assertEquals(nbExpectedMessages, nbLines);
+
+			// Delete log file if no error:
+			fileManager.getLogFile(LogLevel.DEBUG, null).delete();
 
-		}catch(UWSException e){
-			e.printStackTrace(System.err);
-			fail("CAN NOT CREATE THE FILE MANAGER!");
 		}catch(InterruptedException e){
 			e.printStackTrace(System.err);
-			fail("CAN NOT WAIT 3 MINUTES!");
+			fail("CAN NOT WAIT 3 SECONDS!");
+		}catch(Exception e){
+			e.printStackTrace(System.err);
+			fail("CAN NOT CREATE THE FILE MANAGER!");
 		}
 	}
 
diff --git a/test/uws/service/log/DefaultUWSLogTest.java b/test/uws/service/log/TestDefaultUWSLog.java
similarity index 98%
rename from test/uws/service/log/DefaultUWSLogTest.java
rename to test/uws/service/log/TestDefaultUWSLog.java
index 000823f149b36933fb40875e3c74d51ac0541f55..2b39544abb0dc2e16f6deef90f7e28d0be261216 100644
--- a/test/uws/service/log/DefaultUWSLogTest.java
+++ b/test/uws/service/log/TestDefaultUWSLog.java
@@ -11,7 +11,7 @@ import org.junit.Test;
 
 import uws.service.log.UWSLog.LogLevel;
 
-public class DefaultUWSLogTest {
+public class TestDefaultUWSLog {
 
 	@Test
 	public void testCanLog(){