
/*
 * dbXML License, Version 1.0
 *
 *
 * Copyright (c) 1999-2001 The dbXML Group, L.L.C.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by
 *        The dbXML Group (http://www.dbxml.com/)."
 *    Alternately, this acknowledgment may appear in the software
 *    itself, if and wherever such third-party acknowledgments normally
 *    appear.
 *
 * 4. The names "dbXML" and "The dbXML Group" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    info@dbxml.com.
 *
 * 5. Products derived from this software may not be called "dbXML",
 *    nor may "dbXML" appear in their name, without prior written
 *    permission of The dbXML Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE DBXML GROUP OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: CollectionTest.java,v 1.11 2001/08/15 20:06:49 tom Exp $
 */

/*  ASSUMPTIONS
*
*  This code assumes that the collection INSTANCE_NAME/TEST_COLLECTION_NAME exists
*  as well as it's children INSTANCE_NAME/TEST_COLLECTION_CHILD1_NAME and INSTANCE_NAME/TEST_COLLECTION_CHILD2_NAME
*/

import java.io.*;

import junit.framework.*;

import org.xmldb.api.*;
import org.xmldb.api.base.*;
import org.xmldb.api.modules.*;

import org.dbxml.core.corba.db.*;
import org.dbxml.core.corba.db.Collection;


public class CollectionTest extends CorbaAPITestCase {
   
   private boolean exceptioncaught = false;
   
   public CollectionTest(String name) {
      super(name);
   }

   public static junit.framework.Test suite() {
      System.out.println("In CollectionTest.suite() ");
      return new junit.framework.TestSuite(CollectionTest.class);
   }

   public void testGetName() {
      try {
         assertTrue(col.getName().equals(TEST_COLLECTION_NAME));
      } catch (Exception e) {
         fail( e.getMessage() );
      }
   }

   public void testGetCanonicalName() {
      try {
         assertTrue(col.getCanonicalName().equals("/" + INSTANCE_NAME + "/" + TEST_COLLECTION_NAME));
      } catch ( Exception e) {
         fail( e.getMessage() );
      }
   }
   
   public void testGetCollectionManager() {
      CollectionManager colmangotten = null;
      try {
         colmangotten = col.getCollectionManager();
         
         // Verify that a collection manager was returned
         assertNotNull(colman);
                  
      } catch ( Exception e) {
         fail( e.getMessage() );
      } finally {
         colmangotten.remove();
      }
   }
   
   public void testGetParentCollection() {
   
      Collection parentcol = null;
      
      try {
         parentcol = col.getParentCollection();
            
         // Verify that a collection was returned
         assertNotNull(parentcol);
         assertTrue( parentcol.getName().equals(INSTANCE_NAME) );
         
      } catch ( Exception e) {
         fail( e.getMessage() );
      } finally {
         parentcol.remove();
      }
   }
   
   public void testListCollections() {
      String[] colstring = null;
      
      try {
         colstring = col.listCollections();
         
         // Check for null
         assertNotNull(colstring);
         // Verify that 2 child collections found (TEST_COLLECTION_CHILD1_NAME and TEST_COLLECTION_CHILD2_NAME)
         assertTrue( colstring.length == 2 );
         
      } catch ( Exception e) {
         fail( e.getMessage() );
      }
   }

   public void testGetCollection() {
      Collection childcol = null;
      
      try {
         // Try getting a Collection instance for TEST_COLLECTION_CHILD1_NAME
         childcol = col.getCollection(TEST_COLLECTION_CHILD1_NAME);
         assertNotNull(childcol);
         // Verify that we retrived the correct collection
         assertTrue( childcol.getName().equals(TEST_COLLECTION_CHILD1_NAME) );

         // Try getting a Collection instance for TEST_COLLECTION_CHILD1_NAME
         childcol = col.getCollection(TEST_COLLECTION_CHILD2_NAME);
         assertNotNull(childcol);
         // Verify that we retrived the correct collection
         assertTrue( childcol.getName().equals(TEST_COLLECTION_CHILD2_NAME) );
      
         // Try retrieving a bogus collection, should get an COL_COLLECTION_NOT_FOUND faultCode
         try {
            exceptioncaught = false;
            childcol = col.getCollection("lkasdfljkasdf");
         } catch( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.COL_COLLECTION_NOT_FOUND );
         } finally {
            assertTrue( exceptioncaught );
         }
         
         // Try retrieving an empty string
         try {
            exceptioncaught = false;
            childcol = col.getCollection("");
         } catch( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.COL_COLLECTION_NOT_FOUND );
         } finally {
            assertTrue( exceptioncaught );
         }
         
      } catch ( APIException e) {
         fail( e.getMessage() );
      } finally {
         childcol.remove();
      }
   }

   public void testInsertDocument() {
      EncodedBuffer buf = null;
      String doc = null;
      try {
         // Try inserting a blank document, should throw malformed exception
         try {
            exceptioncaught = false;
            doc = "" ;
            buf = new EncodedBuffer(-1, EmptyBytes, doc.getBytes());
            col.insertDocument("Blank",buf);
         } catch ( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.COL_DOCUMENT_MALFORMED );
         } finally {
            assertTrue( exceptioncaught );
         }

         // Try inserting a malformed document, should throw malformed exception
         try {
            exceptioncaught = false;
            doc = "<this is a malformed document>";
            buf = new EncodedBuffer(-1, EmptyBytes, doc.getBytes());
            col.insertDocument("Malformed",buf);
         } catch ( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.COL_DOCUMENT_MALFORMED );
         } finally {
            assertTrue( exceptioncaught );
         }
         
         // Try inserting a well formed document
         doc = "<doc>this is some text</doc>";
         buf = new EncodedBuffer(-1, EmptyBytes, doc.getBytes());
         String insertReturnValue = col.insertDocument("Good",buf);
         assertTrue( insertReturnValue.equals("Good") );
         
      } catch ( APIException e) {
         fail( e.getMessage() );
      }
   }
      
   public void testRemoveDocument() {
      String doc = "<doc>this is some text</doc>";
      EncodedBuffer buf= new EncodedBuffer(-1, EmptyBytes, doc.getBytes() );
      
      try {
         // Insert document to test removal
         col.insertDocument("DocToRemove",buf);
         // Now remove the document if it fails should throw exception, caught below
         col.removeDocument("DocToRemove");
         
         // Try removing a document that doesn't exist, should throw document not found
         try {
            exceptioncaught = false;
            col.removeDocument("bogusdocumentname");
         } catch ( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.COL_DOCUMENT_NOT_FOUND );
         } finally {
            assertTrue( exceptioncaught );
         }
         
         // Try removing a document with an empty string as the name, should throw document not found
         try {
            exceptioncaught = false;
            col.removeDocument("");
         } catch ( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.COL_DOCUMENT_NOT_FOUND );
         } finally {
            assertTrue( exceptioncaught );
         }

      } catch ( Exception e ) {
         fail( e.getMessage() );
      }
   }

   public void testGetDocument() {
      String doc = "<doc>document to be retrieved</doc>";
      EncodedBuffer docbuf= new EncodedBuffer(-1, EmptyBytes, doc.getBytes() );
      EncodedBuffer buf = null;
            
      try {
         // Insert a document, then retrieve it
         col.insertDocument("DocToRetrieve",docbuf);
         buf = col.getDocument("DocToRetrieve", -1);
         
         // Delete the document then try to retrieve, should throw doc not found exception
         col.removeDocument("DocToRetrieve");
         
         try {
            exceptioncaught = false;
            buf = col.getDocument("DocToRetrieve", -1);
         } catch ( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.COL_DOCUMENT_NOT_FOUND );
         } finally {
            assertTrue( exceptioncaught );
         }
         
         // attempt to retrieve a non-existent document
         try {
            exceptioncaught = false;
            EncodedBuffer bogusbuf = col.getDocument("BogusDocumentName", -1 );
         } catch ( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.COL_DOCUMENT_NOT_FOUND );
         } finally {
            assertTrue( exceptioncaught );
         }
         
         // attempt to retrieve a non-existent document
         try {
            exceptioncaught = false;
            EncodedBuffer bogusbuf = col.getDocument("BogusDocumentName", -1 );
         } catch ( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.COL_DOCUMENT_NOT_FOUND );
         } finally {
            assertTrue( exceptioncaught );
         }
         
         // attempt to retrieve a document with a key of the empty string
         try {
            exceptioncaught = false;
            EncodedBuffer bogusbuf = col.getDocument("", -1 );
         } catch ( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.COL_DOCUMENT_NOT_FOUND );
         } finally {
            assertTrue( exceptioncaught );
         }
         
      } catch ( Exception e ) {
         fail( e.getMessage() );
      }
   }
   
   public void testSetDocument() {
   
      String doc1 = XML_PREFIX + "<doc>document to be replaced</doc>";
      EncodedBuffer docbuf1= new EncodedBuffer(-1, EmptyBytes, doc1.getBytes() );
      String doc2 = XML_PREFIX + "<doc>Document to be set to</doc>";
      EncodedBuffer docbuf2= new EncodedBuffer(-1, EmptyBytes, doc2.getBytes() );
      String blankdoc = "" ;
      EncodedBuffer blankbuf = new EncodedBuffer(-1,EmptyBytes, blankdoc.getBytes() );

      try {
      
         // Insert document doc1, then replace with contents from doc2
         col.insertDocument("SetTest", docbuf1 );
         col.setDocument("SetTest", docbuf2 );
         
         // Retrieve the set document, verify that contents identical to those replaced with
         EncodedBuffer setDoc = col.getDocument("SetTest", -1);
         assertTrue( testEquality(docbuf2,setDoc) );
         
         // Try setting a document to empty contents, should throw malformed exception
         try {
            exceptioncaught = false;
            col.setDocument("SetTestEmpty", blankbuf );
         } catch ( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.COL_DOCUMENT_MALFORMED );
         } finally {
            assertTrue( exceptioncaught );
         }
               
      } catch ( Exception e ) {
         fail( e.getMessage() );
      }
   }
   
   public void testQueryDocument() {
   
      // Document returned by a sucessful Xupdate call
      String returnDoc = XML_PREFIX + "<result count=\"1\"><src:modified xmlns:src=\"http://www.dbxml.org/Query\">1</src:modified></result>";
      EncodedBuffer retDocBuf = new EncodedBuffer( -1, EmptyBytes, returnDoc.getBytes() );
      
      // Document that we are going to modify
      String docToModify = XML_PREFIX + "<doc><elem>Element1</elem><elem>Element2</elem></doc>";
      EncodedBuffer docToModifyBuf = new EncodedBuffer(-1, EmptyBytes, docToModify.getBytes() );
      
      // Document that should result from modification
      String modifiedDoc = XML_PREFIX + "<doc><elem>Element2</elem></doc>";
      EncodedBuffer modifiedDocBuf = new EncodedBuffer(-1, EmptyBytes, modifiedDoc.getBytes() );
      
      String XUPDATE_BEGIN = "<xupdate:modifications version=\"1.0\" xmlns:xupdate=\"http://www.xmldb.org/xupdate\">";
      String XUPDATE_END = "</xupdate:modifications>";
      
      // Xupdate query string to run against docToModify, remove the first <elem> element
      String xUpdateString = XUPDATE_BEGIN + "<xupdate:remove select='/doc/elem[1]'/>" + XUPDATE_END ;
   
      try {
         
         // Insert document
         col.insertDocument("XupdateDoc", docToModifyBuf );
         
         // Now run Xupdate against the document, verify that RETURN_DOC was returned
         EncodedBuffer retText = col.queryDocument("XUpdate" , xUpdateString, new NamedVal[0], "XupdateDoc", -1 );
         assertTrue( testEquality( retText, retDocBuf ) );
         
         // Retrieve the document and verify that it is the same as modifiedDoc
         EncodedBuffer retrievedDoc = col.getDocument( "XupdateDoc", -1 );
         assertTrue( testEquality( retrievedDoc, modifiedDocBuf ) );
         
         // Try running an update with a malformed query, Should throw Query compilation error
         String badUpdateString = "<bad document>" ;
         
         try {
            exceptioncaught = false;
            col.queryDocument( "XUpdate", badUpdateString, new NamedVal[0], "XupdateDoc", -1 );
         } catch ( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.QRY_COMPILATION_ERROR );
         } finally {
            assertTrue( exceptioncaught );
         }
         
      } catch ( Exception e ) {
         fail( e.getMessage() );
      }
   }

   public void testQueryCollection() {
   
      // Document returned by a sucessful Xupdate call
      String returnDoc = XML_PREFIX + "<result count=\"1\"><src:modified xmlns:src=\"http://www.dbxml.org/Query\">2</src:modified></result>";
      EncodedBuffer retDocBuf = new EncodedBuffer( -1, EmptyBytes, returnDoc.getBytes() );
      
      // First Document that we are going to modify
      String docToModify1 = XML_PREFIX + "<doc><elem>Element1</elem><elem>Element2</elem></doc>";
      EncodedBuffer docToModifyBuf1 = new EncodedBuffer(-1, EmptyBytes, docToModify1.getBytes() );

      // Second Document that we are going to modify
      String docToModify2 = XML_PREFIX + "<doc><elem>Element1</elem><elem>Element2</elem></doc>";
      EncodedBuffer docToModifyBuf2 = new EncodedBuffer(-1, EmptyBytes, docToModify2.getBytes() );
            
      // Document that should result from modification
      String modifiedDoc = XML_PREFIX + "<doc><elem>Element2</elem></doc>";
      EncodedBuffer modifiedDocBuf = new EncodedBuffer(-1, EmptyBytes, modifiedDoc.getBytes() );
      
      String XUPDATE_BEGIN = "<xupdate:modifications version=\"1.0\" xmlns:xupdate=\"http://www.xmldb.org/xupdate\">";
      String XUPDATE_END = "</xupdate:modifications>";
      
      // Xupdate query string to run against docToModify, remove the first <elem> element
      String xUpdateString = XUPDATE_BEGIN + "<xupdate:remove select='/doc/elem[1]'/>" + XUPDATE_END ;
      
      EncodedBuffer retrievedDoc = null;
   
      try {
         
         // Insert documents
         col.insertDocument("XupdateDoc1", docToModifyBuf1 );
         col.insertDocument("XupdateDoc2", docToModifyBuf2 );
         
         // Now run Xupdate against the documents, verify that RETURN_DOC was returned
         try {
         EncodedBuffer retText = col.queryCollection( "XUpdate" , xUpdateString, new NamedVal[0], -1 );
         assertTrue( testEquality( retText, retDocBuf ) );
         } catch(APIException e) {
            
            System.out.println("Error message = " + e.faultCode );
            e.printStackTrace();
         }
         
         // Retrieve the document1 and verify that it is the same as modifiedDoc
         retrievedDoc = col.getDocument( "XupdateDoc1", -1 );
         assertTrue( testEquality( retrievedDoc, modifiedDocBuf ) );

         // Retrieve the document1 and verify that it is the same as modifiedDoc
         retrievedDoc = col.getDocument( "XupdateDoc2", -1 );
         assertTrue( testEquality( retrievedDoc, modifiedDocBuf ) );
                  
         // Try querying with a malformed query, Should throw Query compilation error
         String badUpdateString = "<bad document>" ;
         
         try {
            exceptioncaught = false;
            col.queryCollection( "XUpdate", badUpdateString, new NamedVal[0], -1 );
         } catch ( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.QRY_COMPILATION_ERROR );
         } finally {
            assertTrue( exceptioncaught );
         }
         
      } catch ( Exception e ) {
         
         e.printStackTrace();
         fail( e.getMessage() );
      }
   }

   public void testGetDocuments() {
   
      // Three documents to be inserted into collection
      String doc1 = XML_PREFIX + "<doc1>doc1</doc1>";
      String doc2 = XML_PREFIX + "<doc2>doc2</doc2>";
      String doc3 = XML_PREFIX + "<doc3>doc3</doc3>";
      EncodedBuffer doc1buf = new EncodedBuffer(-1, EmptyBytes, doc1.getBytes() );
      EncodedBuffer doc2buf = new EncodedBuffer(-1, EmptyBytes, doc2.getBytes() );
      EncodedBuffer doc3buf = new EncodedBuffer(-1, EmptyBytes, doc3.getBytes() );
      
      EncodedBuffer contents = null;
      
      int doccount = 0 ;
   
      try {
      
         // Insert all 3 documents
         col.insertDocument( "doc1", doc1buf );
         col.insertDocument( "doc2", doc2buf );
         col.insertDocument( "doc3", doc3buf );
         
         DocumentSet docset = col.getDocuments();
         
         // TODO - Need a way to verify the contents of the documents returned
         //        Since we aren't guaranteed the order in which they are returned this
         //        isn't currently easy to implement
         
         // Loop over the documents in docset, counting them
         while ( docset.hasMoreDocuments() ) {
            // Get the next document, even though we aren't going to use it
            EncodedBuffer buf = docset.getNextDocument( -1 );
            doccount = doccount + 1;
         }
         
         // Make sure we got the right number of documents
         assertTrue( doccount == 3 );
         
      
      } catch ( Exception e ) {
         fail( e.getMessage() );
      }
   }

   public void testListDocuments() {
   
      // Three documents to be inserted into collection
      String doc1 = XML_PREFIX + "<doc1>doc1</doc1>";
      String doc2 = XML_PREFIX + "<doc2>doc2</doc2>";
      String doc3 = XML_PREFIX + "<doc3>doc3</doc3>";
      EncodedBuffer doc1buf = new EncodedBuffer(-1, EmptyBytes, doc1.getBytes() );
      EncodedBuffer doc2buf = new EncodedBuffer(-1, EmptyBytes, doc2.getBytes() );
      EncodedBuffer doc3buf = new EncodedBuffer(-1, EmptyBytes, doc3.getBytes() );
         
      String[] doclist = null;
   
      try {
      
         // Insert all 3 documents
         col.insertDocument( "doc1", doc1buf );
         col.insertDocument( "doc2", doc2buf );
         col.insertDocument( "doc3", doc3buf );
         
         // Get a list of documents in collection, verify document count
         doclist = col.listDocuments();
         
         assertTrue( doclist.length == 3 );
         
         // Loop over all documents, searching for their Keys and verify index
         for( int i=0 ; i < doclist.length ; i++ ) {
            int index = doclist[i].indexOf("doc" + Integer.toString(i+1) ) ;
            assertTrue( index < 3 && index >= 0 );
         }
         
      } catch ( Exception e ) {
         fail( e.getMessage() );
      }
   }

   public void testGetDocumentCount() {
   
      String doc = XML_PREFIX + "<document>document text</document>";
      EncodedBuffer docbuf = new EncodedBuffer(-1, EmptyBytes, doc.getBytes() );
      
      try {
         // Generate a random number, insert doc into collection that many times
         java.util.Random rand = new java.util.Random();
         int numdocs = rand.nextInt(10);
      
         for ( int i=1 ; i <= numdocs ; i++ ) {
            String docname = "doc" + Integer.toString(i) ;
            col.insertDocument(docname, docbuf);
         }
         
         // check that getdocumentcount returns the correct number of documents
         assertTrue( col.getDocumentCount() == numdocs );
      
      } catch ( Exception e ) {
         fail( e.getMessage() );
      }
   }

   public void testCreateNewOID() {
      try {
         
         // CreateNewOid should always return a 32 character string
         assertTrue( col.createNewOID().length() == 32 );
         
      } catch ( Exception e ) {
         fail( e.getMessage() );
      }
   }
   
   public void test() {
      try {
      
      } catch ( Exception e ) {
         fail( e.getMessage() );
      }
   }

   public void testInvokeXMLObject() {

      String result = "Text from TestXmlObject" ;
      EncodedBuffer resultbuf = new EncodedBuffer(-1, EmptyBytes, result.getBytes() );
      EncodedBuffer output = null;
      
      try {
         
         // Create an XMLObject
         String objectconf = "<xmlobject class=\"org.dbxml.tests.TestXmlObject\" name=\"TestXmlObject\"/>";
         EncodedBuffer objectconfbuf = new EncodedBuffer(-1, EmptyBytes, objectconf.getBytes() );
         colman.createXMLObject( objectconfbuf );
         
         // Invoke object, verify output
         try {
            output = col.invokeXMLObject( "dbxml:///db/tests/TestXmlObject" );
         } catch ( APIException e ) {
            fail( e.getMessage() );
         }
         
         assertTrue( testEquality(output, resultbuf) );
         
         // Try invoking a non-existent object, should get XML Object not found exception
         try {
            exceptioncaught = false;
            col.invokeXMLObject( "bogus object" );
         } catch( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.OBJ_OBJECT_NOT_FOUND );
         } finally {
            assertTrue( exceptioncaught );
         }

         // Try invoking an empty string, should get XML Object not found exception
         try {
            exceptioncaught = false;
            col.invokeXMLObject( "" );
         } catch( APIException e ) {
            exceptioncaught = true;
            assertTrue( e.faultCode == FaultCodes.URI_PARSE_ERROR );
         } finally {
            assertTrue( exceptioncaught );
         }
         
      } catch ( Exception e ) {
         fail( e.getMessage() );
      }
   }
   
}


