/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/testsuite/junit/store/org/apache/slide/store/tamino/datastore/schema/XSchemaTest.java,v 1.3 2004/07/30 06:52:18 ozeigermann Exp $
 * $Revision: 1.3 $
 * $Date: 2004/07/30 06:52:18 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.slide.store.tamino.datastore.schema;

import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Set;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.slide.store.tamino.common.XGlobals;
import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;



/**
 ** A test for the XSchema class.
 **
 ** @version $Revision: 1.3 $
 **
 ** @author rsk@softwareag.com
 **/
public class XSchemaTest extends TestCase {
    private static final String TEST_NAMESPACE = "http://www.software-ag.de/test";
    

    private Document validTsd4SchemaWithNamespace = null;
    private Document tsd4SchemaWithoutDoctype = null;
    private Document tsd3SchemaWithoutDoctype = null;
    
    
    protected static final String PKG = "/org/apache/slide/store/tamino/datastore/schema/resources/";
    
    private static final String TSD_3_SCHEMA_WITHOUT_DOCTYPE_RESOURCE = PKG + "Tsd3SchemaWithoutDoctype.xml";
    
    private static final String VALID_TSD_4_SCHEMA_RESOURCE_WITH_NAMESPACE = PKG + "ValidTSD4SchemaWithNamespace.xml";
    private static final String TSD_4_SCHEMA_WITHOUT_DOCTYPE_RESOURCE = PKG + "Tsd4SchemaWithoutDoctype.xml";
    
    protected static final String VALID_TSD_3_SCHEMA_RESOURCE = PKG + "ValidTSD3Schema.xml";
    protected static final String VALID_TSD_4_SCHEMA_RESOURCE = PKG + "ValidTSD4Schema.xml";
    protected static final String TSD_X_SCHEMA_RESOURCE = PKG + "TSDxSchema.xml";
    protected static final String TSD_3_SCHEMA_WITH_WRONG_ROOT_ELEMENT_RESOURCE = PKG + "Tsd3SchemaWithWrongRootElement.xml";
    protected static final String TSD_4_SCHEMA_WITH_WRONG_ROOT_ELEMENT_RESOURCE = PKG + "Tsd4SchemaWithWrongRootElement.xml";
    
    protected Document tsd3SchemaWithWrongRootElement = null;
    protected Document tsd4SchemaWithWrongRootElement = null;
    protected Document validTsd3Schema = null;
    protected Document validTsd4Schema = null;
    protected Document tsdXSchema = null;
    
    protected SAXBuilder parser = null;
    
    /**
     ** Construct a test case with the given test method name.
     **
     ** @pre   testMethodName != null
     ** @post  true
     **
     ** @param testMethodName   name of the test method that should be invoked
     **/
    public XSchemaTest( String testMethodName ) throws Exception {
        super( testMethodName );
    }
    
    
    /**
     ** Return a TestSuite.
     **
     ** @pre   true
     ** @post  true
     **
     ** @return  TestSuite as a Test
     **/
    public static Test suite() {
        return new TestSuite(  XSchemaTest.class );
    }
    
    
    /**
     ** Construct your fixtures for the test cases.
     **
     ** @pre   true
     ** @post  true
     **
     ** @throws     Exception  if any operation fails.
     **/
    protected void setUp() throws Exception {
        super.setUp();
        parseSchemas();
    }
    
    
    /**
     ** Destruct your fixtures for the test cases.
     **
     ** @pre   true
     ** @post  true
     **
     ** @throws     Exception  if any operation fails.
     **/
    protected void tearDown() throws Exception {
        super.tearDown();
    }
    
    
    /**
     ** Parses the schemas needed for the test.
     **
     ** @pre        true
     ** @post       true
     **
     ** @throws     Exception  if any operation fails.
     **/
    protected void parseSchemas() throws Exception {
        validTsd3Schema = parseDocument(VALID_TSD_3_SCHEMA_RESOURCE);
        validTsd4Schema = parseDocument(VALID_TSD_4_SCHEMA_RESOURCE);
        tsdXSchema = parseDocument(TSD_X_SCHEMA_RESOURCE);
        tsd3SchemaWithWrongRootElement = parseDocument(TSD_3_SCHEMA_WITH_WRONG_ROOT_ELEMENT_RESOURCE);
        tsd4SchemaWithWrongRootElement = parseDocument(TSD_4_SCHEMA_WITH_WRONG_ROOT_ELEMENT_RESOURCE);
        tsd3SchemaWithoutDoctype = parseDocument(TSD_3_SCHEMA_WITHOUT_DOCTYPE_RESOURCE);
        validTsd4SchemaWithNamespace = parseDocument(VALID_TSD_4_SCHEMA_RESOURCE_WITH_NAMESPACE);
        tsd4SchemaWithoutDoctype = parseDocument(TSD_4_SCHEMA_WITHOUT_DOCTYPE_RESOURCE);
    }

    /**
     ** Parses and returns the Document located at the given <code>resourcePath</code>.
     **
     ** @pre        true
     ** @post       true
     **
     ** @param      resourcePath  the path of the resource.
     **
     ** @return     the parsed Document.
     **
     ** @throws     JDOMException  if parsing the document failed.
     **/
    protected Document parseDocument(String resourcePath) throws JDOMException, IOException {
        if (parser == null) {
            parser = new SAXBuilder();
        }
        InputStream inputStream = this.getClass().getResourceAsStream(resourcePath);
        if (inputStream == null) {
            fail("Unable to locate resource " + resourcePath);
        }
        return parser.build(inputStream);
    }
    
    
    
    /**
     ** Tests the newInstance() method.
     **/
    public void testNewInstance() throws Exception {
        
        XSchema schema;
        
        schema = XSchema.newInstance(validTsd3Schema.getRootElement());
        assertEquals(XSchema.class, schema.getClass());
        
        schema = XSchema.newInstance(validTsd4Schema.getRootElement());
        assertEquals(XSchema.class, schema.getClass());
        
        try {
            schema = XSchema.newInstance(null);
            fail("Expected XBadSchemaException since Element is null");
        }
        catch (XBadSchemaException e) {
            assertEquals(XSchema.SCHEMA_ROOT_ELEMENT_MUST_NOT_BE_NULL, e.getMessage());
        }
    }
    
    /**
     ** Tests the getSchemaTypeForTSD3AndHigher() method.
     **/
    public void testGetType() throws Exception {
        XSchemaType schemaType;
        
        assertTrue(XSchema.newInstance(validTsd3Schema.getRootElement()).getType() ==
                   XSchema.newInstance(validTsd3Schema.getRootElement()).getType());
        assertFalse(XSchema.newInstance(validTsd4Schema.getRootElement()).getType() ==
                    XSchema.newInstance(validTsd3Schema.getRootElement()).getType());
        
        try {
            schemaType = XSchema.newInstance(null).getType();
            fail("Expected XBadSchemaException since Element is null");
        }
        catch (XBadSchemaException e) {
            assertEquals(XSchema.SCHEMA_ROOT_ELEMENT_MUST_NOT_BE_NULL, e.getMessage());
        }
        
        try {
            schemaType = XSchema.newInstance(tsdXSchema.getRootElement()).getType();
            fail("Expected XBadSchemaException since version 'TSDx' is not supported");
        }
        catch (XBadSchemaException e) {
            assertEquals(XSchema.VERSION_NOT_SUPPORTED_PREFIX + "TSDx", e.getMessage());
        }
        
        try {
            schemaType = XSchema.newInstance(tsd3SchemaWithWrongRootElement.getRootElement()).getType();
            fail("Expected XBadSchemaException since root element is wrong");
        }
        catch (XBadSchemaException e) {
            assertEquals(XSchema.EXPECTED_ELEMENT_MISSING_PREFIX + XGlobals.SCHEMA, e.getMessage());
        }
    }
    
    
    /**
     ** Returns <code>true</code> if the given <code>doctypeSet</code> contains
     ** an XDoctype where the full qualified name is equal to the given one.
     **
     ** @pre        true
     ** @post       true
     **
     ** @param      doctypeSet  the Set containing the XDoctypes to check.
     ** @param      doctype     the XDoctype to search for.
     **
     ** @return     <code>true</code> if the given <code>doctypeSet</code> contains
     **             an XDoctype where the full qualified name is equal to the given one.
     **/
    protected boolean containsXDoctypeWithEqualFullQualifiedName(Set doctypeSet, XDoctype doctype) {
        
        boolean found = false;
        Iterator iterator = doctypeSet.iterator();
        
        while ( !found && iterator.hasNext() ) {
            found = ((XDoctype)iterator.next()).getFullQualifiedName().equals(doctype.getFullQualifiedName());
        }

        return found;
    }
    
    /**
     ** Tests the constructor that takes a Document as parameter.
     **/
    public void testDocumentConstructor() throws Exception {
        
        XSchema schema = new XSchema(null, validTsd3Schema.getRootElement());
        schema = new XSchema(null, tsd3SchemaWithoutDoctype.getRootElement());
        schema = new XSchema(null, validTsd4Schema.getRootElement());
        schema = new XSchema(null, validTsd4SchemaWithNamespace.getRootElement());
        schema = new XSchema(null, tsd4SchemaWithoutDoctype.getRootElement());
        
        try {
            new XSchema(null, null);
            fail("Expected XBadSchemaException since the schema document was <null>");
        }
        catch (XBadSchemaException e) {
            assertEquals(XSchema.SCHEMA_ROOT_ELEMENT_MUST_NOT_BE_NULL, e.getMessage());
        }
        
        try {
            new XSchema(null, tsd3SchemaWithWrongRootElement.getRootElement());
            fail("Expected XBadSchemaException since the schema root element is wrong");
        }
        catch (XBadSchemaException e) {
            assertEquals(XSchema.EXPECTED_ELEMENT_MISSING_PREFIX  + XGlobals.SCHEMA, e.getMessage());
        }
        
        
        try {
            new XSchema(null, tsd4SchemaWithWrongRootElement.getRootElement());
            fail("Expected XBadSchemaException since the schema root element is wrong");
        }
        catch (XBadSchemaException e) {
            assertEquals(XSchema.EXPECTED_ELEMENT_MISSING_PREFIX  + XGlobals.SCHEMA, e.getMessage());
        }
    }
    
    
    /**
     ** Tests the getDoctypes() method.
     **/
    public void testGetDoctypes() throws Exception {
        
        XSchema schema = new XSchema(null, validTsd3Schema.getRootElement());
        Set doctypeSet = schema.getDoctypes();
        assertNotNull("Set returned by getDoctypes() must not be null", doctypeSet);
        assertEquals(2, doctypeSet.size());
        assertTrue("doctype_1 missing", containsXDoctypeWithEqualFullQualifiedName(doctypeSet, new XDoctype("doctype_1", "")));
        assertTrue("doctype_2 missing", containsXDoctypeWithEqualFullQualifiedName(doctypeSet, new XDoctype("doctype_2", "")));
        
        schema = new XSchema(null, tsd3SchemaWithoutDoctype.getRootElement());
        doctypeSet = schema.getDoctypes();
        assertNotNull("Set returned by getDoctypes() must not be null", doctypeSet);
        assertEquals(0, doctypeSet.size());
        
        schema = new XSchema(null, validTsd4Schema.getRootElement());
        doctypeSet = schema.getDoctypes();
        assertNotNull("Set returned by getDoctypes() must not be null", doctypeSet);
        assertEquals(2, doctypeSet.size());
        assertTrue("doctype_1 missing", containsXDoctypeWithEqualFullQualifiedName(doctypeSet, new XDoctype("doctype_1", "")));
        assertTrue("doctype_2 missing", containsXDoctypeWithEqualFullQualifiedName(doctypeSet, new XDoctype("doctype_2", "")));
        
        schema = new XSchema(null, validTsd4SchemaWithNamespace.getRootElement());
        doctypeSet = schema.getDoctypes();
        assertNotNull("Set returned by getDoctypes() must not be null", doctypeSet);
        assertEquals(2, doctypeSet.size());
        assertTrue("tns:doctype_1 missing", containsXDoctypeWithEqualFullQualifiedName(doctypeSet, new XDoctype("tns:doctype_1", TEST_NAMESPACE)));
        assertTrue("tns:doctype_2 missing", containsXDoctypeWithEqualFullQualifiedName(doctypeSet, new XDoctype("tns:doctype_2", TEST_NAMESPACE)));
        
        schema = new XSchema(null, tsd4SchemaWithoutDoctype.getRootElement());
        doctypeSet = schema.getDoctypes();
        assertNotNull("Set returned by getDoctypes() must not be null", doctypeSet);
        assertEquals(0, doctypeSet.size());
    }
    
    /**
     ** Start precisely this test suite with the commandline interface.
     **
     ** @pre   true
     ** @post  true
     **
     ** @param args   commandline options (none are evaluated)
     **/
    public static void main( String[] args ) {
        junit.textui.TestRunner.run( suite() );
    }
    
}

