package tap.metadata; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.StringBufferInputStream; import java.util.ArrayList; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import adql.db.DBType; import adql.db.DBType.DBDatatype; import tap.TAPException; import tap.metadata.TableSetParser.ForeignKey; @SuppressWarnings("deprecation") public class TestTableSetParser { private static TableSetParser parser = null; private static XMLInputFactory factory = null; private static final String namespaceDef = "xmlns:vs=\"http://www.ivoa.net/xml/VODataService/v1.1\" xmlns:vtm=\"http://www.ivoa.net/xml/VOSITables/v1.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.ivoa.net/xml/VODataService/v1.1 http://vo.ari.uni-heidelberg.de/docs/schemata/VODataService-v1.1.xsd http://www.ivoa.net/xml/VOSITables/v1.0 http://vo.ari.uni-heidelberg.de/docs/schemata/VOSITables-v1.0.xsd\""; @BeforeClass public static void setUpBeforeClass() throws Exception{ // Build an empty parser: parser = new TableSetParser(); // Build the XML factory: factory = XMLInputFactory.newInstance(); } @AfterClass public static void tearDownAfterClass() throws Exception{} @Before public void setUp() throws Exception{} @After public void tearDown() throws Exception{} private static XMLStreamReader buildReader(final String xmlContent) throws XMLStreamException{ return factory.createXMLStreamReader(new StringBufferInputStream(xmlContent)); } private static void close(final XMLStreamReader reader){ if (reader != null){ try{ reader.close(); }catch(Throwable t){} } } @Test public void testGetPosition(){ XMLStreamReader reader = null; try{ // Build a reader with an empty XML document: reader = buildReader(""); assertEquals("[l.1,c.1]", parser.getPosition(reader)); // note: reader.next() is throwing an error on an empty document => no need to test that. close(reader); // Build a reader with a simple XML: reader = buildReader("<A anAttr=\"attrValue\">node value</A>"); // Position before starting reading: assertEquals("[l.1,c.1]", parser.getPosition(reader)); // Position after getting the node: reader.next(); // START_ELEMENT("A") assertEquals("[l.1,c.23]", parser.getPosition(reader)); // The position after getting an attribute should not change: reader.getAttributeLocalName(0); // ATTRIBUTE("attrValue") assertEquals("[l.1,c.23]", parser.getPosition(reader)); // Position after getting the text: reader.next(); // CHARACTERS("node value") assertEquals("[l.1,c.35]", parser.getPosition(reader)); // Position after getting the node ending tag: reader.next(); // END_ELEMENT("A") assertEquals("[l.1,c.37]", parser.getPosition(reader)); // Position once the end reached: reader.next(); // NULL assertEquals("[l.-1,c.-1]", parser.getPosition(reader)); }catch(Exception e){ e.printStackTrace(); if (e instanceof XMLStreamException) fail("Unexpected error while reading the XML content: " + e.getMessage()); else fail("Unexpected error: " + e.getMessage()); }finally{ close(reader); } } @Test public void testGoToEndTag(){ XMLStreamReader reader = null; try{ /* Test with a single empty node AND WITH NULL or "" * => NO TAG SHOULD HAVE BEEN READ: */ // CASE: null reader = buildReader("<A></A>"); parser.goToEndTag(reader, null); assertEquals("[l.1,c.1]", parser.getPosition(reader)); close(reader); // CASE: empty string reader = buildReader("<A></A>"); parser.goToEndTag(reader, ""); assertEquals("[l.1,c.1]", parser.getPosition(reader)); close(reader); /* Test BEFORE having read the start element: * => AN EXCEPTION SHOULD BE THROWN */ reader = buildReader("<A></A>"); try{ parser.goToEndTag(reader, "A"); fail("This function should have failed: the START ELEMENT has not yet been read!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.-1,c.-1] Malformed XML document: missing an END TAG </A>!", e.getMessage()); else throw e; } close(reader); /* Test AFTER having read the start element: * => NORMAL USAGE */ reader = buildReader("<A></A>"); reader.next(); // START ELEMENT("A") parser.goToEndTag(reader, "A"); assertEquals("[l.1,c.8]", parser.getPosition(reader)); close(reader); /* Test AFTER having read the start element: * => NORMAL USAGE with an embedded node */ // search for the root node end: reader = buildReader("<A><B></B></A>"); reader.next(); // START ELEMENT("A") parser.goToEndTag(reader, "A"); assertEquals("[l.1,c.15]", parser.getPosition(reader)); close(reader); // variant with some texts: reader = buildReader("<A><B>super blabla</B></A>"); reader.next(); // START ELEMENT("A") parser.goToEndTag(reader, "A"); assertEquals("[l.1,c.27]", parser.getPosition(reader)); close(reader); // variant with some texts + child node: reader = buildReader("<A><B>super<C>blabla</C></B></A>"); reader.next(); // START ELEMENT("A") parser.goToEndTag(reader, "A"); assertEquals("[l.1,c.33]", parser.getPosition(reader)); close(reader); // search for the child node end: reader = buildReader("<A><B></B></A>"); reader.next(); // START ELEMENT("A") reader.next(); // START ELEMENT("B") parser.goToEndTag(reader, "B"); assertEquals("[l.1,c.11]", parser.getPosition(reader)); close(reader); // variant with some texts: reader = buildReader("<A><B>super blabla</B></A>"); reader.next(); // START ELEMENT("A") reader.next(); // START ELEMENT("B") parser.goToEndTag(reader, "B"); assertEquals("[l.1,c.23]", parser.getPosition(reader)); close(reader); // variant with some texts + child node: reader = buildReader("<A><B>super<C>blabla</C></B></A>"); reader.next(); // START ELEMENT("A") reader.next(); // START ELEMENT("B") parser.goToEndTag(reader, "B"); assertEquals("[l.1,c.29]", parser.getPosition(reader)); close(reader); // Test: Search the end tag while the reader is inside one of its children: reader = buildReader("<A><B>super<C>blabla</C></B></A>"); reader.next(); // START ELEMENT("A") reader.next(); // START ELEMENT("B") parser.goToEndTag(reader, "A"); assertEquals("[l.1,c.33]", parser.getPosition(reader)); close(reader); // Test with a wrong start node name: reader = buildReader("<A></A>"); reader.next(); // START ELEMENT("A") try{ parser.goToEndTag(reader, "B"); fail("This function should have failed: the given node name is wrong (no such node in the XML document)!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.-1,c.-1] Malformed XML document: missing an END TAG </B>!", e.getMessage()); else throw e; } close(reader); // Test with malformed XML document: // CASE: missing end tag for the root node: reader = buildReader("<A><B></B>"); reader.next(); // START ELEMENT("A") try{ parser.goToEndTag(reader, "A"); fail("This function should have failed: the node A has no END TAG!"); }catch(Exception e){ if (e instanceof XMLStreamException) assertEquals("ParseError at [row,col]:[1,11]\nMessage: XML document structures must start and end within the same entity.", e.getMessage()); else throw e; } close(reader); // CASE: missing end tag for a child: reader = buildReader("<A><B></A>"); reader.next(); // START ELEMENT("A") try{ parser.goToEndTag(reader, "A"); fail("This function should have failed: the node B has no END TAG!"); }catch(Exception e){ if (e instanceof XMLStreamException) assertEquals("ParseError at [row,col]:[1,9]\nMessage: The element type \"B\" must be terminated by the matching end-tag \"</B>\".", e.getMessage()); else throw e; } close(reader); // CASE: missing end tag for the child to search: reader = buildReader("<A><B></A>"); reader.next(); // START ELEMENT("A") reader.next(); // START ELEMENT("B") try{ parser.goToEndTag(reader, "B"); fail("This function should have failed: the node B has no END TAG!"); }catch(Exception e){ if (e instanceof XMLStreamException) assertEquals("ParseError at [row,col]:[1,9]\nMessage: The element type \"B\" must be terminated by the matching end-tag \"</B>\".", e.getMessage()); else throw e; } close(reader); }catch(Exception e){ e.printStackTrace(); if (e instanceof XMLStreamException) fail("Unexpected error while reading the XML content: " + e.getMessage()); else fail("Unexpected error: " + e.getMessage()); }finally{ close(reader); } } @Test public void testGetText(){ XMLStreamReader reader = null; String txt; try{ // Test with a simple XML and an empty text: reader = buildReader("<A></A>"); txt = parser.getText(reader); assertEquals(0, txt.length()); assertEquals("[l.1,c.4]", parser.getPosition(reader)); assertEquals(XMLStreamConstants.START_ELEMENT, reader.getEventType()); close(reader); // variant with spaces and tabs: reader = buildReader(" <A></A>"); txt = parser.getText(reader); assertEquals(0, txt.length()); assertEquals("[l.1,c.8]", parser.getPosition(reader)); assertEquals(XMLStreamConstants.START_ELEMENT, reader.getEventType()); close(reader); // variant with line returns: reader = buildReader(" \n <A></A>"); txt = parser.getText(reader); assertEquals(0, txt.length()); assertEquals("[l.2,c.5]", parser.getPosition(reader)); assertEquals(XMLStreamConstants.START_ELEMENT, reader.getEventType()); close(reader); // Test with a single line text: reader = buildReader("<A> Super blabla </A>"); reader.next(); // START ELEMENT("A") txt = parser.getText(reader); assertEquals("Super blabla", txt); assertEquals("[l.1,c.27]", parser.getPosition(reader)); assertEquals(XMLStreamConstants.END_ELEMENT, reader.getEventType()); close(reader); // variant with CDATA: reader = buildReader("<A> Super <![CDATA[blabla ]]> </A>"); reader.next(); // START ELEMENT("A") txt = parser.getText(reader); assertEquals("Super blabla", txt); assertEquals("[l.1,c.39]", parser.getPosition(reader)); assertEquals(XMLStreamConstants.END_ELEMENT, reader.getEventType()); close(reader); // Test with a text of 2 lines: reader = buildReader("<A> Super \n blabla </A>"); reader.next(); // START ELEMENT("A") txt = parser.getText(reader); assertEquals("Super\nblabla", txt); assertEquals("[l.2,c.18]", parser.getPosition(reader)); assertEquals(XMLStreamConstants.END_ELEMENT, reader.getEventType()); close(reader); // same test but with an empty line between both: reader = buildReader("<A> Super \n \n blabla </A>"); reader.next(); // START ELEMENT("A") txt = parser.getText(reader); assertEquals("Super\n\nblabla", txt); assertEquals("[l.3,c.18]", parser.getPosition(reader)); assertEquals(XMLStreamConstants.END_ELEMENT, reader.getEventType()); close(reader); // same test but starting with an empty line: reader = buildReader("<A>\n Super \n bla bla </A>"); reader.next(); // START ELEMENT("A") txt = parser.getText(reader); assertEquals("Super\nbla bla", txt); assertEquals("[l.3,c.20]", parser.getPosition(reader)); assertEquals(XMLStreamConstants.END_ELEMENT, reader.getEventType()); close(reader); // same test but a comment splitting a text part: reader = buildReader("<A> Super \n bla<!-- a super comment --> bla </A>"); reader.next(); // START ELEMENT("A") txt = parser.getText(reader); assertEquals("Super\nbla bla", txt); assertEquals("[l.2,c.44]", parser.getPosition(reader)); assertEquals(XMLStreamConstants.END_ELEMENT, reader.getEventType()); close(reader); }catch(Exception e){ e.printStackTrace(); if (e instanceof XMLStreamException) fail("Unexpected error while reading the XML content: " + e.getMessage()); else fail("Unexpected error: " + e.getMessage()); }finally{ close(reader); } } @Test public void testSearchTable(){ try{ // Create fake metadata: TAPMetadata meta = new TAPMetadata(); TAPSchema schema = new TAPSchema("SA"); schema.addTable("TA"); schema.addTable("TB"); meta.addSchema(schema); schema = new TAPSchema("SB"); schema.addTable("TB"); meta.addSchema(schema); // Create a fake position: final String pos = "[l.10,c.1]"; // Search for an existing table WITHOUT SCHEMA specification: TAPTable t = parser.searchTable("TA", meta, pos); assertEquals("TA", t.getADQLName()); assertEquals("SA", t.getADQLSchemaName()); // variant with a different case: t = parser.searchTable("ta", meta, pos); assertEquals("TA", t.getADQLName()); assertEquals("SA", t.getADQLSchemaName()); // Search for an existing table WITH SCHEMA specification: t = parser.searchTable("SA.TA", meta, pos); assertEquals("TA", t.getADQLName()); assertEquals("SA", t.getADQLSchemaName()); // variant with a different case: t = parser.searchTable("sa.ta", meta, pos); assertEquals("TA", t.getADQLName()); assertEquals("SA", t.getADQLSchemaName()); // Search with a wrong table name: try{ parser.searchTable("TC", meta, pos); fail("This test should have not failed: there is no table named TC in the given metadata."); }catch(Exception e){ if (e instanceof TAPException) assertEquals(pos + " Unknown table: \"TC\"!", e.getMessage()); else throw e; } // variant with a correct schema name: try{ parser.searchTable("SA.TC", meta, pos); fail("This test should have not failed: there is no table named SA.TC in the given metadata."); }catch(Exception e){ if (e instanceof TAPException) assertEquals(pos + " Unknown table: \"SA.TC\"!", e.getMessage()); else throw e; } // Search with a wrong schema name: try{ parser.searchTable("SC.TB", meta, pos); fail("This test should have not failed: there is no schema named SC in the given metadata."); }catch(Exception e){ if (e instanceof TAPException) assertEquals(pos + " Unknown table: \"SC.TB\"!", e.getMessage()); else throw e; } // Search with an ambiguous table name (missing schema name): try{ parser.searchTable("TB", meta, pos); fail("This test should have not failed: there are two table named TB ; a schema name is required to choose the table to select."); }catch(Exception e){ if (e instanceof TAPException) assertEquals(pos + " Unresolved table: \"TB\"! Several tables have the same name but in different schemas (here: SA.TB, SB.TB). You must prefix this table name by a schema name (expected syntax: \"schema.table\").", e.getMessage()); else throw e; } // Provide a schema + table name with a wrong syntax (missing table name or schema name): try{ parser.searchTable(".TB", meta, pos); fail("This test should have not failed: the schema name is missing before the '.'."); }catch(Exception e){ if (e instanceof TAPException) assertEquals(pos + " Incorrect full table name - \".TB\": empty schema name!", e.getMessage()); else throw e; } try{ parser.searchTable("SB.", meta, pos); fail("This test should have not failed: the table name is missing after the '.'."); }catch(Exception e){ if (e instanceof TAPException) assertEquals(pos + " Incorrect full table name - \"SB.\": empty table name!", e.getMessage()); else throw e; } try{ parser.searchTable("toto.SB.TB", meta, pos); fail("This test should have not failed: the table name is missing after the '.'."); }catch(Exception e){ if (e instanceof TAPException) assertEquals(pos + " Incorrect full table name - \"toto.SB.TB\": only a schema and a table name can be specified (expected syntax: \"schema.table\")\"!", e.getMessage()); else throw e; } }catch(Exception e){ e.printStackTrace(); fail("Unexpected error: " + e.getMessage()); } } @Test public void testParseFKey(){ XMLStreamReader reader = null; try{ // Test while search outside from the foreignKey node: reader = buildReader("<table><foreignKey><targetTable>SA.TB</targetTable><utype>truc.chose</utype><description>Foreign key\ndescription.</description><fkColumn><fromColumn>col1</fromColumn><targetColumn>col2</targetColumn></fkColumn></foreignKey></table>"); reader.next(); // START ELEMENT("table") try{ parser.parseFKey(reader); fail("This test should have failed: the reader has not just read the \"foreignKey\" START ELEMENT tag."); }catch(Exception e){ if (e instanceof IllegalStateException) assertEquals("[l.1,c.8] Illegal usage of TableSetParser.parseFKey(XMLStreamParser)! This function can be called only when the reader has just read the START ELEMENT tag \"foreignKey\".", e.getMessage()); else throw e; }finally{ close(reader); } // Test with a complete and correct XML foreignKey node: reader = buildReader("<foreignKey><targetTable>SA.TB</targetTable><utype>truc.chose</utype><description>Foreign key\ndescription.</description><fkColumn><fromColumn>col1</fromColumn><targetColumn>col2</targetColumn></fkColumn></foreignKey>"); reader.next(); // START ELEMENT("foreignKey") ForeignKey fk = parser.parseFKey(reader); assertEquals("SA.TB", fk.targetTable); assertEquals("[l.1,c.45]", fk.targetTablePosition); assertEquals("truc.chose", fk.utype); assertEquals("Foreign key\ndescription.", fk.description); assertEquals(1, fk.keyColumns.size()); assertEquals("col2", fk.keyColumns.get("col1")); close(reader); // variant with some comments: reader = buildReader("<foreignKey><!-- Here, we are inside! --><targetTable><!-- coucou -->SA.TB</targetTable><description>Foreign key\ndescription.</description><fkColumn><fromColumn>col1</fromColumn><targetColumn>col2</targetColumn></fkColumn><!-- Here is the end! --></foreignKey><!-- Nothing more! -->"); reader.next(); // START ELEMENT("foreignKey") fk = parser.parseFKey(reader); assertEquals("SA.TB", fk.targetTable); assertEquals("Foreign key\ndescription.", fk.description); assertEquals(1, fk.keyColumns.size()); assertEquals("col2", fk.keyColumns.get("col1")); close(reader); // variant with texts at unapropriate places: reader = buildReader("<foreignKey>Here, we are <![CDATA[inside!]]><targetTable>SA.TB</targetTable><description>Foreign key\ndescription.</description><fkColumn><fromColumn>col1</fromColumn><targetColumn>col2</targetColumn></fkColumn>Here is the end!</foreignKey>Nothing more!"); reader.next(); // START ELEMENT("foreignKey") fk = parser.parseFKey(reader); assertEquals("SA.TB", fk.targetTable); assertEquals("Foreign key\ndescription.", fk.description); assertEquals(1, fk.keyColumns.size()); assertEquals("col2", fk.keyColumns.get("col1")); close(reader); // Test with a missing targetTable: reader = buildReader("<foreignKey><description>Foreign key\ndescription.</description><fkColumn><fromColumn>col1</fromColumn><targetColumn>col2</targetColumn></fkColumn></foreignKey>"); reader.next(); // START ELEMENT("foreignKey") try{ parser.parseFKey(reader); fail("This test should have failed: the targetTable node is missing!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.2,c.123] Missing \"targetTable\"!", e.getMessage()); }finally{ close(reader); } // variant with duplicated targetTable: reader = buildReader("<foreignKey><targetTable>SA.TB</targetTable><targetTable>SA.TA</targetTable><description>Foreign key\ndescription.</description><fkColumn><fromColumn>col1</fromColumn><targetColumn>col2</targetColumn></fkColumn></foreignKey>"); reader.next(); // START ELEMENT("foreignKey") try{ parser.parseFKey(reader); fail("This test should have failed: the targetTable node is duplicated!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.58] Only one \"targetTable\" element can exist in a /tableset/schema/table/foreignKey!", e.getMessage()); }finally{ close(reader); } // Test with a missing fkColumn: reader = buildReader("<foreignKey><targetTable>SA.TB</targetTable><description>Foreign key\ndescription.</description></foreignKey>"); reader.next(); // START ELEMENT("foreignKey") try{ parser.parseFKey(reader); fail("This test should have failed: at least 1 fkColumn node is missing!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.2,c.40] Missing at least one \"fkColumn\"!", e.getMessage()); }finally{ close(reader); } // variant with several fkColumn: reader = buildReader("<foreignKey><targetTable>SA.TB</targetTable><description>Foreign key\ndescription.</description><fkColumn><fromColumn>col1</fromColumn><targetColumn>col2</targetColumn></fkColumn><fkColumn><fromColumn>col3</fromColumn><targetColumn>col4</targetColumn></fkColumn></foreignKey>"); reader.next(); // START ELEMENT("foreignKey") fk = parser.parseFKey(reader); assertEquals("SA.TB", fk.targetTable); assertEquals("Foreign key\ndescription.", fk.description); assertEquals(2, fk.keyColumns.size()); assertEquals("col2", fk.keyColumns.get("col1")); assertEquals("col4", fk.keyColumns.get("col3")); close(reader); // Test with a missing fromColumn: reader = buildReader("<foreignKey><targetTable>SA.TB</targetTable><fkColumn><targetColumn>col2</targetColumn></fkColumn></foreignKey>"); reader.next(); // START ELEMENT("foreignKey") try{ parser.parseFKey(reader); fail("This test should have failed: the fromColumn node is missing!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.99] Missing \"fromColumn\"!", e.getMessage()); }finally{ close(reader); } // variant with several fromColumn: reader = buildReader("<foreignKey><targetTable>SA.TB</targetTable><fkColumn><fromColumn>col1</fromColumn><fromColumn>col1bis</fromColumn><targetColumn>col2</targetColumn></fkColumn></foreignKey>"); reader.next(); // START ELEMENT("foreignKey") try{ parser.parseFKey(reader); fail("This test should have failed: sereval fromColumn are found!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.96] Only one \"fromColumn\" element can exist in a /tableset/schema/table/foreignKey/fkColumn !", e.getMessage()); }finally{ close(reader); } // Test with a missing targetColumn: reader = buildReader("<foreignKey><targetTable>SA.TB</targetTable><fkColumn><fromColumn>col1</fromColumn></fkColumn></foreignKey>"); reader.next(); // START ELEMENT("foreignKey") try{ parser.parseFKey(reader); fail("This test should have failed: the targetColumn node is missing!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.95] Missing \"targetColumn\"!", e.getMessage()); }finally{ close(reader); } // variant with several fromColumn: reader = buildReader("<foreignKey><targetTable>SA.TB</targetTable><fkColumn><fromColumn>col1</fromColumn><targetColumn>col2</targetColumn><targetColumn>col2bis</targetColumn></fkColumn></foreignKey>"); reader.next(); // START ELEMENT("foreignKey") try{ parser.parseFKey(reader); fail("This test should have failed: several targetColumn are found!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.131] Only one \"targetColumn\" element can exist in a /tableset/schema/table/foreignKey/fkColumn !", e.getMessage()); }finally{ close(reader); } // Test with a additional node: reader = buildReader("<foreignKey><super>blabla</super><foo>anything</foo><targetTable>SA.TB</targetTable><fkColumn><fromColumn>col1</fromColumn><targetColumn>col2</targetColumn></fkColumn></foreignKey>"); reader.next(); // START ELEMENT("foreignKey") fk = parser.parseFKey(reader); assertEquals("SA.TB", fk.targetTable); assertNull(fk.description); assertEquals(1, fk.keyColumns.size()); assertEquals("col2", fk.keyColumns.get("col1")); close(reader); }catch(Exception e){ e.printStackTrace(); if (e instanceof XMLStreamException) fail("Unexpected error while reading the XML content: " + e.getMessage()); else fail("Unexpected error: " + e.getMessage()); }finally{ close(reader); } } @Test public void testParseDataType(){ XMLStreamReader reader = null; try{ // Test while search outside from the dataType node: reader = buildReader("<column " + namespaceDef + "><dataType arraysize=\"*\">char</dataType></column>"); reader.next(); // START ELEMENT("column") try{ parser.parseDataType(reader); fail("This test should have failed: the reader has not just read the \"dataType\" START ELEMENT tag."); }catch(Exception e){ if (e instanceof IllegalStateException) assertEquals("[l.1,c.408] Illegal usage of TableSetParser.parseDataType(XMLStreamParser)! This function can be called only when the reader has just read the START ELEMENT tag \"dataType\".", e.getMessage()); else throw e; }finally{ close(reader); } // Test with a correct TAP type: reader = buildReader("<column " + namespaceDef + "><dataType xsi:type=\"vs:TAPType\">varchar</dataType></column>"); reader.next(); // START ELEMENT("column") reader.next(); // START ELEMENT("dataType") DBType dt = parser.parseDataType(reader); assertEquals(DBDatatype.VARCHAR, dt.type); assertEquals(-1, dt.length); close(reader); // Test with a correct VOTable type: reader = buildReader("<dataType " + namespaceDef + " xsi:type=\"vs:VOTableType\" arraysize=\"*\">char</dataType>"); reader.next(); // START ELEMENT("dataType") dt = parser.parseDataType(reader); assertEquals(DBDatatype.VARCHAR, dt.type); assertEquals(-1, dt.length); close(reader); // Test with a missing xsi:type: reader = buildReader("<dataType " + namespaceDef + " arraysize=\"*\">char</dataType>"); reader.next(); // START ELEMENT("dataType") try{ parser.parseDataType(reader); fail("This test should have failed: the attribute xsi:type is missing!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.424] Missing attribute \"xsi:type\" (where xsi = \"" + TableSetParser.XSI_NAMESPACE + "\")! Expected attribute value: vs:VOTableType or vs:TAPType, where vs = " + TableSetParser.VODATASERVICE_NAMESPACE + ".", e.getMessage()); else throw e; }finally{ close(reader); } // variant with a wrong namespace prefix reader = buildReader("<dataType " + namespaceDef + " xsj:type=\"vs:VOTableType\" arraysize=\"*\">char</dataType>"); try{ reader.next(); // START ELEMENT("dataType") fail("This test should have failed: the prefix of the xsi:type attribute is wrong!"); }catch(Exception e){ if (e instanceof XMLStreamException) assertEquals("ParseError at [row,col]:[1,450]\nMessage: http://www.w3.org/TR/1999/REC-xml-names-19990114#AttributePrefixUnbound?dataType&xsj:type&xsj", e.getMessage()); else throw e; }finally{ close(reader); } // variant with a missing namespace prefix: reader = buildReader("<dataType xsi:type=\"vs:VOTableType\" arraysize=\"*\">char</dataType>"); try{ reader.next(); // START ELEMENT("dataType") fail("This test should have failed: the namespace xsi is not defined!"); }catch(Exception e){ if (e instanceof XMLStreamException) assertEquals("ParseError at [row,col]:[1,51]\nMessage: http://www.w3.org/TR/1999/REC-xml-names-19990114#AttributePrefixUnbound?dataType&xsi:type&xsi", e.getMessage()); else throw e; }finally{ close(reader); } // Test with an unsupported xsi:type: reader = buildReader("<dataType " + namespaceDef + " xsi:type=\"vs:foo\" arraysize=\"*\">char</dataType>"); reader.next(); // START ELEMENT("dataType") try{ parser.parseDataType(reader); fail("This test should have failed: the type foo is not defined in VODataService!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.457] Unsupported type: \"vs:foo\"! Expected: vs:VOTableType or vs:TAPType, where vs = " + TableSetParser.VODATASERVICE_NAMESPACE + ".", e.getMessage()); else throw e; }finally{ close(reader); } // variant with no namespace prefix in front of the wrong type: reader = buildReader("<dataType " + namespaceDef + " xsi:type=\"foo\" arraysize=\"*\">char</dataType>"); reader.next(); // START ELEMENT("dataType") try{ parser.parseDataType(reader); fail("This test should have failed: the namespace prefix is missing in the value of xsi:type!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.439] Unresolved type: \"foo\"! Missing namespace prefix.", e.getMessage()); else throw e; }finally{ close(reader); } // Test with a missing datatype: reader = buildReader("<dataType " + namespaceDef + " xsi:type=\"vs:TAPType\"></dataType>"); reader.next(); // START ELEMENT("dataType") try{ parser.parseDataType(reader); fail("This test should have failed: the datatype value is missing!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.443] Missing column datatype!", e.getMessage()); else throw e; }finally{ close(reader); } // variant with a wrong datatype: reader = buildReader("<dataType " + namespaceDef + " xsi:type=\"vs:TAPType\">foo</dataType>"); reader.next(); // START ELEMENT("dataType") try{ parser.parseDataType(reader); fail("This test should have failed: the datatype value is unknown!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.446] Unknown TAPType: \"foo\"!", e.getMessage()); else throw e; }finally{ close(reader); } }catch(Exception e){ e.printStackTrace(); if (e instanceof XMLStreamException) fail("Unexpected error while reading the XML content: " + e.getMessage()); else fail("Unexpected error: " + e.getMessage()); }finally{ close(reader); } } @Test public void testParseColumn(){ XMLStreamReader reader = null; try{ // Test while search outside from the column node: reader = buildReader("<table " + namespaceDef + "><column std=\"true\"><name>col1</name><description>Column\ndescription.</description><dataType xsi:type=\"vs:TAPType\">SMALLINT</dataType><utype>truc.chose</utype><ucd>t.c</ucd><unit>deg</unit><flag>nullable</flag><flag>primary</flag><flag>indexed</flag></column></table>"); reader.next(); // START ELEMENT("table") try{ parser.parseColumn(reader); fail("This test should have failed: the reader has not just read the \"column\" START ELEMENT tag."); }catch(Exception e){ if (e instanceof IllegalStateException) assertEquals("[l.1,c.407] Illegal usage of TableSetParser.parseColumn(XMLStreamParser)! This function can be called only when the reader has just read the START ELEMENT tag \"column\".", e.getMessage()); else throw e; }finally{ close(reader); } // Test with a complete and correct XML column node: reader = buildReader("<table " + namespaceDef + "><column std=\"true\"><name>col1</name><description>Column\ndescription.</description><dataType xsi:type=\"vs:TAPType\">SMALLINT</dataType><utype>truc.chose</utype><ucd>t.c</ucd><unit>deg</unit><flag>nullable</flag><flag>primary</flag><flag>indexed</flag></column></table>"); reader.next(); // START ELEMENT("table") reader.next(); // START ELEMENT("column") TAPColumn col = parser.parseColumn(reader); assertEquals("col1", col.getADQLName()); assertEquals("Column\ndescription.", col.getDescription()); assertEquals(DBDatatype.SMALLINT, col.getDatatype().type); assertEquals(-1, col.getDatatype().length); assertEquals("truc.chose", col.getUtype()); assertEquals("t.c", col.getUcd()); assertEquals("deg", col.getUnit()); assertTrue(col.isIndexed()); assertTrue(col.isPrincipal()); assertTrue(col.isNullable()); assertTrue(col.isStd()); close(reader); // variant with entering inside the foreignKey node (as it is done by TableSetParser): reader = buildReader("<column " + namespaceDef + "><name>col1</name><description>Column\ndescription.</description><dataType xsi:type=\"vs:TAPType\">SMALLINT</dataType><utype>truc.chose</utype><ucd>t.c</ucd><unit>deg</unit></column>"); reader.next(); // START ELEMENT("column") col = parser.parseColumn(reader); assertEquals("col1", col.getADQLName()); assertEquals("Column\ndescription.", col.getDescription()); assertEquals(DBDatatype.SMALLINT, col.getDatatype().type); assertEquals(-1, col.getDatatype().length); assertEquals("truc.chose", col.getUtype()); assertEquals("t.c", col.getUcd()); assertEquals("deg", col.getUnit()); assertFalse(col.isIndexed()); assertFalse(col.isPrincipal()); assertFalse(col.isNullable()); assertFalse(col.isStd()); close(reader); // variant with some comments: reader = buildReader("<column " + namespaceDef + "><!-- Here we are inside! --><name>col1</name><!-- Here blabla about the column. --><description>Column\ndescription.</description><dataType xsi:type=\"vs:TAPType\">SMALLINT</dataType><utype>truc.chose</utype><ucd>t.c</ucd><unit>deg</unit><!-- Here is the end! --></column><!-- Nothing more! -->"); reader.next(); // START ELEMENT("column") col = parser.parseColumn(reader); assertEquals("col1", col.getADQLName()); assertEquals("Column\ndescription.", col.getDescription()); assertEquals(DBDatatype.SMALLINT, col.getDatatype().type); assertEquals(-1, col.getDatatype().length); assertEquals("truc.chose", col.getUtype()); assertEquals("t.c", col.getUcd()); assertEquals("deg", col.getUnit()); assertFalse(col.isIndexed()); assertFalse(col.isPrincipal()); assertFalse(col.isNullable()); assertFalse(col.isStd()); close(reader); // variant with texts at unapropriate places: reader = buildReader("<column " + namespaceDef + ">Here we are <![CDATA[inside!]]><name>col1</name><description>Column\ndescription.</description><dataType xsi:type=\"vs:TAPType\">SMALLINT</dataType><utype>truc.chose</utype><ucd>t.c</ucd><unit>deg</unit></column>Nothing more!"); reader.next(); // START ELEMENT("column") col = parser.parseColumn(reader); assertEquals("col1", col.getADQLName()); assertEquals("Column\ndescription.", col.getDescription()); assertEquals(DBDatatype.SMALLINT, col.getDatatype().type); assertEquals(-1, col.getDatatype().length); assertEquals("truc.chose", col.getUtype()); assertEquals("t.c", col.getUcd()); assertEquals("deg", col.getUnit()); assertFalse(col.isIndexed()); assertFalse(col.isPrincipal()); assertFalse(col.isNullable()); assertFalse(col.isStd()); close(reader); // Test with a missing "name" node: reader = buildReader("<column></column>"); reader.next(); // START ELEMENT("column") try{ parser.parseColumn(reader); fail("This test should have failed: the \"name\" node is missing!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.18] Missing column \"name\"!", e.getMessage()); }finally{ close(reader); } // variant with duplicated "name": reader = buildReader("<column><name>col1</name><name>colA</name></column>"); reader.next(); // START ELEMENT("column") try{ parser.parseColumn(reader); fail("This test should have failed: the \"name\" node is duplicated!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.32] Only one \"name\" element can exist in a /tableset/schema/table/column!", e.getMessage()); }finally{ close(reader); } // Test with a additional node: reader = buildReader("<column><name>col1</name><dbname>colA</dbname><foo>blabla</foo></column>"); reader.next(); // START ELEMENT("foreignKey") col = parser.parseColumn(reader); assertEquals("col1", col.getADQLName()); assertNull(col.getDescription()); assertEquals(DBDatatype.UNKNOWN, col.getDatatype().type); assertEquals(-1, col.getDatatype().length); assertNull(col.getUtype()); assertNull(col.getUcd()); assertNull(col.getUnit()); assertFalse(col.isIndexed()); assertFalse(col.isPrincipal()); assertFalse(col.isNullable()); assertFalse(col.isStd()); close(reader); }catch(Exception e){ e.printStackTrace(); if (e instanceof XMLStreamException) fail("Unexpected error while reading the XML content: " + e.getMessage()); else fail("Unexpected error: " + e.getMessage()); }finally{ close(reader); } } @Test public void testParseTable(){ XMLStreamReader reader = null; ArrayList<ForeignKey> fkeys = new ArrayList<ForeignKey>(0); try{ // Test while search outside from the table node: reader = buildReader("<schema><table><name>TableA</name></table></schema>"); reader.next(); // START ELEMENT("schema") try{ parser.parseTable(reader, fkeys); fail("This test should have failed: the reader has not just read the \"table\" START ELEMENT tag."); }catch(Exception e){ if (e instanceof IllegalStateException) assertEquals("[l.1,c.9] Illegal usage of TableSetParser.parseTable(XMLStreamParser)! This function can be called only when the reader has just read the START ELEMENT tag \"table\".", e.getMessage()); else throw e; }finally{ close(reader); fkeys.clear(); } // Test with a complete and correct XML table node: reader = buildReader("<table><name>TableA</name><description>Table \ndescription.</description><utype>truc.chose</utype><title>Table title</title><column><name>col1</name></column><foreignKey><targetTable>TB</targetTable><fkColumn><fromColumn>col1</fromColumn><targetColumn>col2</targetColumn></fkColumn></foreignKey></table>"); reader.next(); // START ELEMENT("table") TAPTable t = parser.parseTable(reader, fkeys); assertEquals("TableA", t.getADQLName()); assertEquals("Table\ndescription.", t.getDescription()); assertEquals("truc.chose", t.getUtype()); assertEquals("Table title", t.getTitle()); assertEquals(1, t.getNbColumns()); assertNotNull(t.getColumn("col1")); assertEquals(0, t.getNbForeignKeys()); assertEquals(1, fkeys.size()); assertEquals("TB", fkeys.get(0).targetTable); assertEquals(t, fkeys.get(0).fromTable); close(reader); fkeys.clear(); // variant with some comments: reader = buildReader("<table><!-- Here we are inside! --><name>TableA</name><description>Table \ndescription.</description><utype><!-- Table UType -->truc.chose</utype><title>Table title</title><column><name>col1</name></column><foreignKey><targetTable>TB</targetTable><fkColumn><fromColumn>col1</fromColumn><targetColumn>col2</targetColumn></fkColumn></foreignKey></table><!-- Nothing more! -->"); reader.next(); // START ELEMENT("table") t = parser.parseTable(reader, fkeys); assertEquals("TableA", t.getADQLName()); assertEquals("Table\ndescription.", t.getDescription()); assertEquals("truc.chose", t.getUtype()); assertEquals("Table title", t.getTitle()); assertEquals(1, t.getNbColumns()); assertNotNull(t.getColumn("col1")); assertEquals(0, t.getNbForeignKeys()); assertEquals(1, fkeys.size()); assertEquals("TB", fkeys.get(0).targetTable); assertEquals(t, fkeys.get(0).fromTable); close(reader); fkeys.clear(); // variant with texts at unapropriate places: reader = buildReader("<table>Here we are <![CDATA[inside!]]><name>TableA</name><description>Table \ndescription.</description><utype><!-- Table UType -->truc.chose</utype><title>Table title</title><column><name>col1</name></column><foreignKey><targetTable>TB</targetTable><fkColumn><fromColumn>col1</fromColumn><targetColumn>col2</targetColumn></fkColumn></foreignKey></table>Nothing more!"); reader.next(); // START ELEMENT("table") t = parser.parseTable(reader, fkeys); assertEquals("TableA", t.getADQLName()); assertEquals("Table\ndescription.", t.getDescription()); assertEquals("truc.chose", t.getUtype()); assertEquals("Table title", t.getTitle()); assertEquals(1, t.getNbColumns()); assertNotNull(t.getColumn("col1")); assertEquals(0, t.getNbForeignKeys()); assertEquals(1, fkeys.size()); assertEquals("TB", fkeys.get(0).targetTable); assertEquals(t, fkeys.get(0).fromTable); close(reader); fkeys.clear(); // Test with a missing "name" node: reader = buildReader("<table></table>"); reader.next(); // START ELEMENT("table") try{ parser.parseTable(reader, fkeys); fail("This test should have failed: the \"name\" node is missing!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.16] Missing table \"name\"!", e.getMessage()); }finally{ close(reader); fkeys.clear(); } // variant with duplicated "name": reader = buildReader("<table><name>Table1</name><name>TableA</name></table>"); reader.next(); // START ELEMENT("table") try{ parser.parseTable(reader, fkeys); fail("This test should have failed: the \"name\" node is duplicated!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.33] Only one \"name\" element can exist in a /tableset/schema/table!", e.getMessage()); }finally{ close(reader); fkeys.clear(); } // Test with a additional node: reader = buildReader("<table><name>TableA</name><dbname>SuperTableA</dbname><foo>blabla</foo></table>"); reader.next(); // START ELEMENT("table") t = parser.parseTable(reader, fkeys); assertEquals("TableA", t.getADQLName()); assertNull(t.getDescription()); assertNull(t.getUtype()); assertNull(t.getTitle()); assertEquals(0, t.getNbColumns()); assertEquals(0, t.getNbForeignKeys()); assertEquals(0, fkeys.size()); close(reader); fkeys.clear(); }catch(Exception e){ e.printStackTrace(); if (e instanceof XMLStreamException) fail("Unexpected error while reading the XML content: " + e.getMessage()); else fail("Unexpected error: " + e.getMessage()); }finally{ close(reader); fkeys.clear(); } } @Test public void testParseSchema(){ XMLStreamReader reader = null; ArrayList<ForeignKey> fkeys = new ArrayList<ForeignKey>(0); try{ // Test while search outside from the schema node: reader = buildReader("<tableset><schema><name>PublicSchema</name></schema></tableset>"); reader.next(); // START ELEMENT("tableset") try{ parser.parseSchema(reader, fkeys); fail("This test should have failed: the reader has not just read the \"schema\" START ELEMENT tag."); }catch(Exception e){ if (e instanceof IllegalStateException) assertEquals("[l.1,c.11] Illegal usage of TableSetParser.parseSchema(XMLStreamParser)! This function can be called only when the reader has just read the START ELEMENT tag \"schema\".", e.getMessage()); else throw e; }finally{ close(reader); fkeys.clear(); } // Test with a complete and correct XML table node: reader = buildReader("<schema><name>PublicSchema</name><description>Schema \ndescription.</description><utype>truc.chose</utype><title>Schema title</title><table><name>TableA</name></table></schema>"); reader.next(); // START ELEMENT("schema") TAPSchema s = parser.parseSchema(reader, fkeys); assertEquals("PublicSchema", s.getADQLName()); assertEquals("Schema\ndescription.", s.getDescription()); assertEquals("truc.chose", s.getUtype()); assertEquals("Schema title", s.getTitle()); assertEquals(1, s.getNbTables()); assertNotNull(s.getTable("TableA")); close(reader); fkeys.clear(); // variant with some comments: reader = buildReader("<schema><!-- Here we are inside! --><name>PublicSchema <!-- schema name --></name><description>Schema \ndescription.</description><utype>truc.chose</utype><title>Schema title</title><table><name>TableA</name></table></schema><!-- Nothing more! -->"); reader.next(); // START ELEMENT("schema") s = parser.parseSchema(reader, fkeys); assertEquals("PublicSchema", s.getADQLName()); assertEquals("Schema\ndescription.", s.getDescription()); assertEquals("truc.chose", s.getUtype()); assertEquals("Schema title", s.getTitle()); assertEquals(1, s.getNbTables()); assertNotNull(s.getTable("TableA")); close(reader); fkeys.clear(); // variant with texts at unapropriate places: reader = buildReader("<schema>Here we are <![CDATA[inside!]]><name>PublicSchema <!-- schema name --></name><description>Schema \ndescription.</description><utype>truc.chose</utype><title>Schema title</title><table><name>TableA</name></table></schema>Nothing more!"); reader.next(); // START ELEMENT("schema") s = parser.parseSchema(reader, fkeys); assertEquals("PublicSchema", s.getADQLName()); assertEquals("Schema\ndescription.", s.getDescription()); assertEquals("truc.chose", s.getUtype()); assertEquals("Schema title", s.getTitle()); assertEquals(1, s.getNbTables()); assertNotNull(s.getTable("TableA")); close(reader); fkeys.clear(); // Test with a missing "name" node: reader = buildReader("<schema></schema>"); reader.next(); // START ELEMENT("schema") try{ parser.parseSchema(reader, fkeys); fail("This test should have failed: the \"name\" node is missing!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.18] Missing schema \"name\"!", e.getMessage()); }finally{ close(reader); fkeys.clear(); } // variant with duplicated "name": reader = buildReader("<schema><name>PublicSchema</name><name>PrivateSchema</name></schema>"); reader.next(); // START ELEMENT("schema") try{ parser.parseSchema(reader, fkeys); fail("This test should have failed: the \"name\" node is duplicated!"); }catch(Exception e){ if (e instanceof TAPException) assertEquals("[l.1,c.40] Only one \"name\" element can exist in a /tableset/schema!", e.getMessage()); }finally{ close(reader); fkeys.clear(); } // Test with a additional node: reader = buildReader("<schema><name>PublicSchema</name><dbname>public</dbname><foo>blabla</foo></schema>"); reader.next(); // START ELEMENT("schema") s = parser.parseSchema(reader, fkeys); assertEquals("PublicSchema", s.getADQLName()); assertNull(s.getDescription()); assertNull(s.getUtype()); assertNull(s.getTitle()); assertEquals(0, s.getNbTables()); close(reader); fkeys.clear(); }catch(Exception e){ e.printStackTrace(); if (e instanceof XMLStreamException) fail("Unexpected error while reading the XML content: " + e.getMessage()); else fail("Unexpected error: " + e.getMessage()); }finally{ close(reader); fkeys.clear(); } } }