/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/wvcm/test/junit/src/org/apache/wvcm/test/SearchTest.java,v 1.3 2004/07/30 06:52:33 ozeigermann Exp $
 * $Revision: 1.3 $
 * $Date: 2004/07/30 06:52:33 $
 *
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2003 The Apache Software Foundation.  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 acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Slide", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache 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 APACHE SOFTWARE FOUNDATION 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * [Additional notices, if required by prior licensing conditions]
 *
 */

package org.apache.wvcm.test;

import javax.wvcm.SearchToken.*;

import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.wvcm.ControllableFolder;
import javax.wvcm.ControllableResource;
import javax.wvcm.PropertyNameList;
import javax.wvcm.PropertyNameList.AttributeName;
import javax.wvcm.PropertyNameList.PropertyName;
import javax.wvcm.Resource;
import javax.wvcm.SearchToken;
import javax.wvcm.WvcmException;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.apache.wvcm.test.common.AbstractTest;
import org.apache.wvcm.test.common.util.ReasonCodeChecker;


/**
 * Test class for Search functionality in WVCM implementation.
 *
 * @author <a href="mailto:peter.nevermann@softwareag.com">Peter Nevermann</a>
 * @version $Revision: 1.3 $
 */
public class SearchTest extends AbstractTest {
	
	private static Logger logger = Logger.getLogger("org.apache.wvcm.test.SearchTest");
	
	private String testFolderRootPath = "SearchTest";
	private String testFolderChildPath = "SearchTestChild_1";
	private String testFilePath_1 = "searchTest_1.xml";
	private String testFilePath_2 = "searchTest_2.xml";
	private String testFilePath_3 = "searchTest_3.xml";
	
	private PropertyNameList displayNameProps =
		new PropertyNameList( new PropertyName[]{
				PropertyName.DISPLAY_NAME} );
	
	/**
	 * Default Constructor
	 *
	 * @param    testName            Name of the test to run.
	 *
	 * @throws   Exception
	 *
	 */
    public SearchTest(String testName) throws Exception {
		super(testName);
		//		resourcePath = rootFolderPath()+"/test.xml";
		//		folderPath = rootFolderPath()+"/foo";
    }
    
    /**
	 * Method suite
	 *
	 * @return   a Test
	 */
    public static Test suite() {
		return new TestSuite(SearchTest.class);
    }
    
    /**
	 * Start test suite contained in this class using the text interface. If a
	 * parameter is passed, it will use it as a test name and run only that test
	 * case.
	 *
	 * @param args   commandline options (first argument = test method name to run)
	 *
	 * @throws   Exception
	 */
    public static void main( String[] args ) throws Exception{
		if (args.length == 1) {
			TestSuite testSuite = new TestSuite();
			testSuite.addTest(new SearchTest(args[0]));
			junit.textui.TestRunner.run(testSuite);
		}
		else {
			junit.textui.TestRunner.run( suite() );
		}
    }
    
    /**
	 * Test common setup.
	 *
	 * @throws   Exception
	 */
    protected void setUp() throws Exception {
		super.setUp ();
		
		assertTrue("Folder creation failed.",
				   createFolderStructure());
    }
    
    /**
	 * Tears down the fixture, for example, close a network connection.
	 * This method is called after a test is executed.
	 *
	 * @throws   Exception
	 */
    protected void tearDown() throws Exception {
    }
	
	/**
	 * Creates a folder structure like:
	 * <ul>
	 * <li><store>/SearchTest
	 * <li><store>/SearchTest/searchTest_1.xml
	 * <li><store>/SearchTest/SearchTestChild_1
	 * <li><store>/SearchTest/SearchTestChild_1/searchTest_2.xml
	 * <li><store>/SearchTest/SearchTestChild_1/searchTest_3.xml
	 * It does not control any folder nor write any property. It updates the member
	 * variables with the complete path to the resource/folder.
	 *
	 * @return   True if the creation had no trouble.
	 *
	 * @throws   Exception
	 *
	 */
	private boolean createFolderStructure() throws Exception {
		boolean isCreationCorrect = true;
		try {
			testFolderRootPath = rootFolderPath()
				.concat("/").concat(testFolderRootPath);
			location = provider.location( testFolderRootPath );
			createControllableFolder(location);
			
			testFilePath_1 = testFolderRootPath.concat("/").concat(testFilePath_1);
			location = provider.location( testFilePath_1);
			createControllableResource(location);
			
			testFolderChildPath = testFolderRootPath
				.concat("/").concat(testFolderChildPath);
			location = provider.location( testFolderChildPath);
			createControllableFolder(location);
			
			testFilePath_2 = testFolderChildPath
				.concat("/").concat(testFilePath_2);
			location = provider.location(testFilePath_2);
			createControllableResource(location);
			
			testFilePath_3 = testFolderChildPath
				.concat("/").concat(testFilePath_3);
			location = provider.location(testFilePath_3);
			createControllableResource(location);
		}
		catch (WvcmException unexpected) {
			if(logger.isLoggable(Level.CONFIG)) {
				logger.config("Exception while creating folder structure:\n"
							  + unexpected.getMessage());
			}
			isCreationCorrect = false;
		}
		return isCreationCorrect;
	}
    
	/**
	 * <ul>
	 * <li>Create a folder and a resource.
	 * <li>Make a search on the resource for the property DISPLAY_NAME.
	 * <li>Check resource received (no display name should be there).
	 * <li>Set the display name of the resource and repeat the search.
	 * <li>Check search result for the displayname.
	 *
	 * @throws   Exception
	 */
    public void testDoSearchResource() throws Exception {
		location = provider.location( testFilePath_1 );
		resource = location.controllableResource();
		// First make a search for the display name without setting display name.
		// Since search is on a resx, only one result is expected.
		List searchResult = resource.doSearch(displayNameProps, null);
		try {
			((ControllableResource)searchResult.get(0)).getDisplayName();
			fail("Value_Unavailble was expected here.");
		}
		catch (WvcmException expected) {
			assertEquals("Unexpected Reason code received.",
						 "PROPERTY_MISSING",
						 ReasonCodeChecker.getReasonCodeAsString(expected));
		}
		
		
		//resource = (ControllableResource)resource.doReadProperties(displayNameProps);
		String testDisplayName = "testDisplayName.xml";
		resource.setDisplayName(testDisplayName);
		resource.doWriteProperties();
		
		searchResult = resource.doSearch(displayNameProps, null);
		
		assertEquals("Unexpected DisplayName in searched resource.",
					 testDisplayName,
						 ((ControllableResource)searchResult.get(0)).getDisplayName());
    }
	
	/**
	 * <ul>
	 * <li>Create folder structure (in setUp).
	 * <li>Make a search in the root folder for the display name using a null token.
	 * <li>Check result contains all items.
	 *
	 * @throws Exception
	 */
	public void testDoSearchNullToken() throws Exception {
		location = provider.location( testFolderRootPath);
		folder = (ControllableFolder)location.folder();
		
		List searchResult = folder.doSearch(displayNameProps, null);
		assertEquals("Unexpected number of found items.",
					 5,
					 searchResult.size());
	}
    
	/**
	 * <ul>
	 * <li>Create folder structure (in setup).
	 * <li>Add attributes to the resources/folders (Attribute added will be
	 * the same as ist name).
	 * <li>Search for all resx containing the attribute.
	 * <li>Check search result and attributes are correct.
	 *
	 * @throws   Exception
	 *
	 */
    public void testDoSearchAttributes() throws Exception {
		AttributeName testAttribute = new AttributeName("http://my.namespace", "my-att");
		
		// Add wished attributes to the folders and resources.
		location = provider.location( testFolderRootPath);
		folder = (ControllableFolder)location.folder();
		
		// Write attributes in folder/resources.
		// <store>/SearchTest
		folder.setAttribute( testAttribute,
							testFolderRootPath.substring(testFolderRootPath.lastIndexOf("/") + 1) );
		folder.doWriteProperties();
		// <store>/SearchTest/searchTest_1.xml
		location = provider.location( testFilePath_1);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_1.substring(testFilePath_1.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1
		location = provider.location(testFolderChildPath);
		ControllableFolder subfolder = (ControllableFolder)location.folder();
		subfolder.setAttribute( testAttribute,
							   testFolderChildPath.substring(testFolderChildPath.lastIndexOf("/") + 1) );
		subfolder.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1/searchTest_2.xml
		location = provider.location( testFilePath_2);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_2.substring(testFilePath_2.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1/searchTest_3.xml
		location = provider.location( testFilePath_3);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_3.substring(testFilePath_3.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		
		// Start searching for all attributes.
		List results;
		Iterator ri;
		PropertyNameList myAttProps =
			new PropertyNameList( new PropertyName[]{testAttribute} );
		
		results = folder.doSearch( myAttProps, null );
		ri = results.iterator();
		Resource r;
		String resxLocation;
		try {
			while( ri.hasNext() ) {
				r =(Resource)ri.next();
				resxLocation = r.location().string();
				assertEquals("Unexpected attribute value in " + r,
							 resxLocation.substring(resxLocation.lastIndexOf("/") + 1),
							 r.getAttribute(testAttribute));
			}
		}
		catch (WvcmException unexpected) {
			fail("Unexpected exception thrown while getting attributes:\n"
				 + unexpected.getMessage());
		}
    }
	
	/**
	 * <ul>
	 * <li>Create folder structure (in setup).
	 * <li>Add attributes to the resources/folders (Attribute added will be
	 * the same as ist name).
	 * <li>Search for all resx containing xml in the attribute.
	 * <li>Check result.
	 *
	 * @throws Exception
	 */
	public void testDoSearchTokenContains() throws Exception {
		AttributeName testAttribute = new AttributeName("http://my.namespace", "my-att");
		
		// Add wished attributes to the folders and resources.
		location = provider.location( testFolderRootPath);
		folder = (ControllableFolder)location.folder();
		
		// Write attributes in folder/resources.
		// <store>/SearchTest
		folder.setAttribute( testAttribute,
							testFolderRootPath.substring(testFolderRootPath.lastIndexOf("/") + 1) );
		folder.doWriteProperties();
		// <store>/SearchTest/searchTest_1.xml
		location = provider.location( testFilePath_1);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_1.substring(testFilePath_1.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1
		location = provider.location(testFolderChildPath);
		ControllableFolder subfolder = (ControllableFolder)location.folder();
		subfolder.setAttribute( testAttribute,
							   testFolderChildPath.substring(testFolderChildPath.lastIndexOf("/") + 1) );
		subfolder.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1/searchTest_2.xml
		location = provider.location( testFilePath_2);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_2.substring(testFilePath_2.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1/searchTest_3.xml
		location = provider.location( testFilePath_3);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_3.substring(testFilePath_3.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		
		// Start search
		List results;
		Iterator ri;
		PropertyNameList myAttProps =
			new PropertyNameList( new PropertyName[]{testAttribute} );
		
		Resource tempResx;
		Expression expression =
			new PropertyExpression(testAttribute,
								   "xml",
								   PropOperator.CONTAINS,
								   null);
		
		SearchToken searchToken =
			new SearchToken(new SearchCondition(expression));
		results = folder.doSearch( myAttProps, searchToken );
		ri = results.iterator();
		while( ri.hasNext() ) {
			tempResx = (Resource)ri.next();
			assertTrue("Result of Search does not satisfy the search token (contains xml).",
					   tempResx.getAttribute(testAttribute).toString().indexOf("xml") != -1);
		}
	}
	
	/**
	 * <ul>
	 * <li>Create folder structure (in setup).
	 * <li>Add attributes to the resources/folders (Attribute added will be
	 * the same as ist name).
	 * <li>Search for all resx containing xml in the attribute and sort them.
	 * <li>Check result.
	 *
	 * @throws Exception
	 */
	public void testDoSearchSorting() throws Exception {
		AttributeName testAttribute = new AttributeName("http://my.namespace", "my-att");
		
		// Add wished attributes to the folders and resources.
		location = provider.location( testFolderRootPath);
		folder = (ControllableFolder)location.folder();
		
		// Write attributes in folder/resources.
		// <store>/SearchTest
		folder.setAttribute( testAttribute,
							testFolderRootPath.substring(testFolderRootPath.lastIndexOf("/") + 1) );
		folder.doWriteProperties();
		// <store>/SearchTest/searchTest_1.xml
		location = provider.location( testFilePath_1);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_1.substring(testFilePath_1.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1
		location = provider.location(testFolderChildPath);
		ControllableFolder subfolder = (ControllableFolder)location.folder();
		subfolder.setAttribute( testAttribute,
							   testFolderChildPath.substring(testFolderChildPath.lastIndexOf("/") + 1) );
		subfolder.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1/searchTest_2.xml
		location = provider.location( testFilePath_2);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_2.substring(testFilePath_2.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1/searchTest_3.xml
		location = provider.location( testFilePath_3);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_3.substring(testFilePath_3.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		
		// Start search
		PropertyNameList myAttProps =
			new PropertyNameList( new PropertyName[]{testAttribute} );
		
		Expression expression =
			new PropertyExpression(testAttribute,
								   "xml",
								   PropOperator.CONTAINS,
								   null);
		
		SearchToken searchToken =
			new SearchToken(new SearchCondition(expression));
		
		SortCriterion[] sortCriteriaDescending = {
			new SortCriterion(
				PropertyName.DISPLAY_NAME,
				OrderDirection.DESCENDING,
				null)
		};
		searchToken
			= new SearchToken(new SearchCondition(expression),
							  sortCriteriaDescending,
							  Depth.INFINITY,
							  null);
		
		List resultsDescending = folder.doSearch( myAttProps, searchToken );
		
		// repeat the search but now ascending.
		SortCriterion[] sortCriteriaAscending = {
			new SortCriterion(
				PropertyName.DISPLAY_NAME, OrderDirection.ASCENDING, null)
		};
		searchToken
			= new SearchToken(new SearchCondition(expression),
							  sortCriteriaAscending,
							  Depth.INFINITY,
							  null);
		
		List resultsAscending = folder.doSearch( myAttProps, searchToken );
		assertEquals("Different number of items when ascending/descending.",
					 resultsDescending.size(),
					 resultsAscending.size());
		int sizeOfResult = resultsDescending.size();
		for (int i=0; i<sizeOfResult; i++) {
			assertEquals("Unexpected sorting in ascending || descending results",
						 resultsAscending.get(i).toString(),
						 resultsDescending.get(sizeOfResult-i-1).toString());
		}
	}
	
	/**
	 * <ul>
	 * <li>Create folder structure (in setup).
	 * <li>Add attributes to the resources/folders (Attribute added will be
	 * the same as ist name).
	 * <li>Search for all resx with the attribute giving different limits.
	 * <li>Search using different Limits.
	 * <li>Check result.
	 *
	 * @throws Exception
	 */
	public void testDoSearchLimit() throws Exception {
		AttributeName testAttribute = new AttributeName("http://my.namespace", "my-att");
		
		// Add wished attributes to the folders and resources.
		location = provider.location( testFolderRootPath);
		folder = (ControllableFolder)location.folder();
		
		// Write attributes in folder/resources.
		// <store>/SearchTest
		folder.setAttribute( testAttribute,
							testFolderRootPath.substring(testFolderRootPath.lastIndexOf("/") + 1) );
		folder.doWriteProperties();
		// <store>/SearchTest/searchTest_1.xml
		location = provider.location( testFilePath_1);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_1.substring(testFilePath_1.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1
		location = provider.location(testFolderChildPath);
		ControllableFolder subfolder = (ControllableFolder)location.folder();
		subfolder.setAttribute( testAttribute,
							   testFolderChildPath.substring(testFolderChildPath.lastIndexOf("/") + 1) );
		subfolder.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1/searchTest_2.xml
		location = provider.location( testFilePath_2);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_2.substring(testFilePath_2.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1/searchTest_3.xml
		location = provider.location( testFilePath_3);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_3.substring(testFilePath_3.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		
		// Start search
		PropertyNameList myAttProps =
			new PropertyNameList( new PropertyName[]{testAttribute} );
		
		Expression expression =
			new PropertyExpression(testAttribute,
								   "xml",
								   PropOperator.CONTAINS,
								   null);
		
		SearchToken searchToken =
			new SearchToken(new SearchCondition(expression));
		
		SortCriterion[] sortCriteriaDescending = {
			new SortCriterion(
				PropertyName.DISPLAY_NAME,
				OrderDirection.DESCENDING,
				null)
		};
		// Search with limit on 1
		searchToken
			= new SearchToken(new SearchCondition(expression),
							  sortCriteriaDescending,
							  Depth.INFINITY,
							  new Integer(1));
		
		List resultsDescending = folder.doSearch( myAttProps, searchToken );
		assertEquals("Unexpected number of result items in search (1).",
					 1,
					 resultsDescending.size());
		
		// Search with limit on 2
		searchToken
			= new SearchToken(new SearchCondition(expression),
							  sortCriteriaDescending,
							  Depth.INFINITY,
							  new Integer(2));
		
		resultsDescending = folder.doSearch( myAttProps, searchToken );
		assertEquals("Unexpected number of result items in search (2).",
					 2,
					 resultsDescending.size());
		// Search with limit on 3
		searchToken
			= new SearchToken(new SearchCondition(expression),
							  sortCriteriaDescending,
							  Depth.INFINITY,
							  new Integer(3));
		
		resultsDescending = folder.doSearch( myAttProps, searchToken );
		assertEquals("Unexpected number of result items in search (3).",
					 3,
					 resultsDescending.size());
		// Search with limit on 0
		searchToken
			= new SearchToken(new SearchCondition(expression),
							  sortCriteriaDescending,
							  Depth.INFINITY,
							  new Integer(0));
		
		resultsDescending = folder.doSearch( myAttProps, searchToken );
		assertEquals("Unexpected number of result items in search (0).",
					 0,
					 resultsDescending.size());
	}
	
	/**
	 * <ul>
	 * <li>Create folder structure (in setup).
	 * <li>Add attributes to the resources/folders (Attribute added will be
	 * the same as ist name).
	 * <li>Search for all resx with the attribute using the operator "LIKE".
	 * <li>Check result.
	 *
	 * @throws Exception
	 */
	public void testDoSearchCriteriaLike() throws Exception {
		AttributeName testAttribute = new AttributeName("http://my.namespace", "my-att");
		
		// Add wished attributes to the folders and resources.
		location = provider.location( testFolderRootPath);
		folder = (ControllableFolder)location.folder();
		
		// Write attributes in folder/resources.
		// <store>/SearchTest
		folder.setAttribute( testAttribute,
							testFolderRootPath.substring(testFolderRootPath.lastIndexOf("/") + 1) );
		folder.doWriteProperties();
		// <store>/SearchTest/searchTest_1.xml
		location = provider.location( testFilePath_1);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_1.substring(testFilePath_1.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1
		location = provider.location(testFolderChildPath);
		ControllableFolder subfolder = (ControllableFolder)location.folder();
		subfolder.setAttribute( testAttribute,
							   testFolderChildPath.substring(testFolderChildPath.lastIndexOf("/") + 1) );
		subfolder.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1/searchTest_2.xml
		location = provider.location( testFilePath_2);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_2.substring(testFilePath_2.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		// <store>/SearchTest/SearchTestChild_1/searchTest_3.xml
		location = provider.location( testFilePath_3);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute,
							  testFilePath_3.substring(testFilePath_3.lastIndexOf("/") + 1) );
		resource.doWriteProperties();
		
		// Start search
		PropertyNameList myAttProps =
			new PropertyNameList( new PropertyName[]{testAttribute} );
		
		Resource tempResx;
		
		// ONLY PARTIALLY SUPPORTED BY TAMINO WEBDAV SERVER
		Expression expression =
			new PropertyExpression(testAttribute, "%x%", PropOperator.LIKE, new Boolean(true));
		SearchToken searchToken =
			new SearchToken(new SearchCondition(expression));
		List searchResult = folder.doSearch( myAttProps, searchToken );
		assertEquals("Unexpected number of items in search result.",
					 3,
					 searchResult.size());
		
		// now searching for something only contained in one of the resources...
		expression =
			new PropertyExpression(testAttribute, "%3%", PropOperator.LIKE, new Boolean(true));
		searchToken =
			new SearchToken(new SearchCondition(expression));
		searchResult = folder.doSearch( myAttProps, searchToken );
		assertEquals("Unexpected number of items in search result.",
					 1,
					 searchResult.size());
		
	}
    
	/**
	 * <ul>
	 * <li>Create folder structure (in setup).
	 * <li>Add attributes to the resources/folders.
	 * <li>Seach using different nested expressions: AND, OR
	 * <li>Search as well for the content type in the nested expressions.
	 * <li>Check results of search are correct.
	 *
	 * @throws   Exception
	 *
	 */
	public void testDoSearchWithNestedExpression() throws Exception {
		AttributeName testAttribute1 = new AttributeName("http://my.namespace", "my-att-1");
		AttributeName testAttribute2 = new AttributeName("http://my.namespace", "my-att-2");
		
		location = provider.location( testFolderRootPath);
		folder = (ControllableFolder)location.folder();
		folder.setAttribute( testAttribute1, "x" );
		folder.setAttribute( testAttribute2, "x" );
		folder.doWriteProperties();
		
		// <store>/SearchTest/searchTest_1.xml
		location = provider.location( testFilePath_1);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute1, "x" );
		resource.setAttribute( testAttribute2, "y" );
		resource.doWriteProperties();
		
		// <store>/SearchTest/SearchTestChild_1
		location = provider.location(testFolderChildPath);
		ControllableFolder subfolder = (ControllableFolder)location.folder();
		subfolder.setAttribute( testAttribute1, "y" );
		subfolder.setAttribute( testAttribute2, "x" );
		subfolder.doWriteProperties();
		
		// <store>/SearchTest/SearchTestChild_1/searchTest_2.xml
		location = provider.location( testFilePath_2);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute1, "y" );
		resource.setAttribute( testAttribute2, "y" );
		resource.doWriteProperties();
		
		// <store>/SearchTest/SearchTestChild_1/searchTest_3.xml
		location = provider.location( testFilePath_3);
		resource = location.controllableResource();
		resource.setAttribute( testAttribute1, "x" );
		resource.setAttribute( testAttribute2, "y" );
		resource.doWriteProperties();
		
		List results;
		PropertyNameList wantedprops =
			new PropertyNameList(
			new PropertyName[]{
				PropertyName.CONTENT_TYPE,
					testAttribute1,
					testAttribute2} );
		Expression[] terms = {
			new PropertyExpression(testAttribute1, "x", PropOperator.EQ, null),
				new PropertyExpression(testAttribute2, "y", PropOperator.EQ, null)
		};
		Expression expression;
		SearchToken searchToken;
		
		// do search for all things with those attributes.
		results = folder.doSearch( wantedprops, null );
		assertEquals("Unexpected number of items in result (5).",
					 5,
					 results.size());
		
		// do search with attribute1=x AND attribute2=y
		expression = new NestedExpression(terms, LogOperator.AND);
		searchToken =
			new SearchToken(new SearchCondition(expression));
		results = folder.doSearch( wantedprops, searchToken );
		assertEquals("Unexpected number of items in result (2).",
					 2,
					 results.size());
		
		// do search with attribute1=x OR attribute2=y
		expression = new NestedExpression(terms, LogOperator.OR);
		searchToken =
			new SearchToken(new SearchCondition(expression));
		results = folder.doSearch( wantedprops, searchToken );
		assertEquals("Unexpected number of items in result (4).",
					 4,
					 results.size());
		
		// search for resx with content-type=text/xml and (att1=x OR att2=y)
		Expression[] upperterms = {
			new PropertyExpression( PropertyName.CONTENT_TYPE, "text/xml", PropOperator.EQ, null),
				new NestedExpression(terms, LogOperator.OR)
		};
		expression = new NestedExpression(upperterms, LogOperator.AND);
		searchToken =
			new SearchToken(new SearchCondition(expression));
		results = folder.doSearch( wantedprops, searchToken );
		assertEquals("Unexpected number of items in result (3).",
					 3,
					 results.size());
		
		// search for NOT(content-type=text/xml AND (att1=x OR att2!=y))
		terms = new Expression[]{
			new PropertyExpression(testAttribute1, "x", PropOperator.EQ, null),
				new PropertyExpression(testAttribute2, "y", PropOperator.EQ, null).negate()
		};
		upperterms = new Expression[]{
			new PropertyExpression( PropertyName.CONTENT_TYPE, "text/xml", PropOperator.EQ, null),
				new NestedExpression(terms, LogOperator.OR)
		};
		expression = new NestedExpression(upperterms, LogOperator.AND).negate();
		searchToken =
			new SearchToken(new SearchCondition(expression));
		results = folder.doSearch( wantedprops, searchToken );
		assertEquals("Unexpected number of items in result (1).",
					 1,
					 results.size());
		
		// search will return nothing, since none of the resources has a content.
		// kept to check how to do this in the future.
		// TODO: ADD CONTENT TO THE FILES FOR THIS CHECK TO BE DONE.
		Expression[] orTerms = {
			new ContentExpression("/test[text()=\"Hello World!\"]", ContOperator.XPATH),
				new ContentExpression("/test[@name=\"tamino\"]", ContOperator.XPATH)
		};
		expression =
			new NestedExpression(orTerms, LogOperator.OR);
		searchToken =
			new SearchToken(new SearchCondition(expression));
		results = folder.doSearch( wantedprops, searchToken );
		assertEquals("Unexpected number of items in result (0).",
					 0,
					 results.size());
    }
    
	/**
	 * <ul>
	 * <li>Add content to the files created in the setup.
	 * <li>Make different searches on the content of the file,
	 * including sorting and nested conditions.
	 * <li>Check results.
	 *
	 * @throws   Exception
	 *
	 */
	// TODO: ADD DOCUMENTATION
	// TODO: REMOVE SYSTEM.OUT.PRINTLN. ADD CHECKS.
    public void testContentExpression() throws Exception {
		// create the resources: /foo/, /foo/a.xml, /foo/bar/, /foo/bar/b.xml, /foo/bar/c.xml
		PropertyNameList wantedprops =
			new PropertyNameList( new PropertyName[]{PropertyName.CONTENT_IDENTIFIER} );
		
		location = provider.location( testFolderRootPath);
		folder = (ControllableFolder)location.folder();
		
		// <store>/SearchTest/searchTest_1.xml
		location = provider.location( testFilePath_1);
		resource = location.controllableResource();
		String cid = propsHelper.getContentIdentifier(resource);
		InputStream testInputStream = null;
		try {
			testInputStream = getClass().getResourceAsStream(testResourcesRoot + "test.xml");
			resource.doWriteContent(testInputStream, cid);
			resource.doControl();
		}
		finally {
			if (testInputStream != null)
				testInputStream.close();
		}
		
		location = provider.location(testFolderChildPath);
		ControllableFolder subfolder = (ControllableFolder)location.folder();
		
		
		location = provider.location( testFilePath_2);
		resource = location.controllableResource();
		cid = propsHelper.getContentIdentifier(resource);
		try {
			testInputStream = getClass().getResourceAsStream(testResourcesRoot + "test2.xml");
			resource.doWriteContent(testInputStream, cid);
			resource.doControl();
		}
		finally {
			if (testInputStream != null)
				testInputStream.close();
		}
		
		location = provider.location( testFilePath_3);
		resource = location.controllableResource();
		cid = propsHelper.getContentIdentifier(resource);
		try {
			testInputStream = getClass().getResourceAsStream(testResourcesRoot + "test3.xml");
			resource.doWriteContent(testInputStream, cid);
			resource.doControl();
		}
		finally {
			if (testInputStream != null)
				testInputStream.close();
		}
		
		List results;
		Iterator ri;
		wantedprops =
			new PropertyNameList( new PropertyName[]{PropertyName.DISPLAY_NAME} );
		SearchToken searchToken;
		Expression expression;
		SortCriterion[] sortCriteria;
		
		// search for content containing the word "Hello".
		expression =
			new ContentExpression("Hello", ContOperator.CONTAINS);
		searchToken =
			new SearchToken(new SearchCondition(expression));
		results = folder.doSearch( wantedprops, searchToken );
		assertEquals("Unexpected number of items in result (3).",
					 3,
					 results.size());
		// search for content containing the word "World".
		expression =
			new ContentExpression("World", ContOperator.CONTAINS);
		searchToken =
			new SearchToken(new SearchCondition(expression));
		results = folder.doSearch( wantedprops, searchToken );
		assertEquals("Unexpected number of items in result (1).",
					 1,
					 results.size());
		
		// search for "World" OR "@name=tamino"
		Expression[] terms = {
			new ContentExpression("World", ContOperator.CONTAINS),
				new ContentExpression("/test[@name=\"tamino\"]", ContOperator.XPATH)
		};
		expression =
			new NestedExpression(terms, LogOperator.OR);
		searchToken =
			new SearchToken(new SearchCondition(expression));
		results = folder.doSearch( wantedprops, searchToken );
		assertEquals("Unexpected number of items in result (2).",
					 2,
					 results.size());
		
		// search using xpath
		String nspUri = "http://my.namespace.org";
		AttributeName p_att_1 = new XPathAttributeName(nspUri, "pseudo-1", "/test/a[1]");
		AttributeName p_att_2 = new XPathAttributeName(nspUri, "pseudo-2", "/test/@name");
		wantedprops =
			new PropertyNameList( new PropertyName[]{p_att_1, p_att_2} );
		expression = new ContentExpression("/test[@name=\"tamino\"]", ContOperator.XPATH);
		searchToken =
			new SearchToken(new SearchCondition(expression));
		results = folder.doSearch( wantedprops, searchToken );
		assertEquals("Unexpected number of items in result (1).",
					 1,
					 results.size());
		
		AttributeName p_att = new XPathAttributeName(nspUri, "pseudo", "/test/@color");
		wantedprops =
			new PropertyNameList( new PropertyName[]{p_att} );
		expression = new ContentExpression("/test", ContOperator.XPATH);
		sortCriteria = new SortCriterion[]{
			new SortCriterion(p_att, OrderDirection.ASCENDING, null)
		};
		searchToken
			= new SearchToken(new SearchCondition(expression), sortCriteria, null, null);
		results = folder.doSearch( wantedprops, searchToken );
		assertEquals("Unexpected number of items in result (3).",
					 3,
					 results.size());
		
		expression = new ContentExpression("/test", ContOperator.XPATH);
		sortCriteria = new SortCriterion[]{
			new SortCriterion(p_att, OrderDirection.ASCENDING, null),
				new SortCriterion(PropertyName.CONTENT_LENGTH, OrderDirection.DESCENDING, null),
				new SortCriterion(PropertyName.CONTENT_LANGUAGE, OrderDirection.DESCENDING, null)
		};
		searchToken
			= new SearchToken(new SearchCondition(expression), sortCriteria, null, null);
		wantedprops =
			new PropertyNameList( new PropertyName[]{PropertyName.CONTENT_LENGTH} );
		results = folder.doSearch( wantedprops, searchToken );
		ri = results.iterator();
		long contentLengthItem = Long.MAX_VALUE;
		Resource tempResource ;
//		String attributeOfResult = "ZZZZZZZZZZZZZZ";
		while( ri.hasNext() ) {
			tempResource = (Resource)ri.next();
			assertTrue("Incorrect order from content length.",
						contentLengthItem >= tempResource.getContentLength());
			contentLengthItem = tempResource.getContentLength();
			
			// FIXME: CHECK IF IT IS POSSIBLE TO MAKE THE CHECK ON THIS AFTER ANSWER FROM MARTIN.
//			System.out.println(attributeOfResult);
//			System.out.println((String)tempResource.getAttribute(p_att));
//			System.out.println(attributeOfResult.compareTo((String)tempResource.getAttribute(p_att)));
//			assertTrue("Incorrect order in the attribute.",
//					   attributeOfResult.compareTo((String)tempResource.getAttribute(p_att)) >= 0);
//			attributeOfResult = (String)tempResource.getAttribute(p_att);
		}
    }
}


