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é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é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é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(){