/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/testsuite/junit/store/org/apache/slide/store/tamino/datastore/search/XBasicExpressionFactoryTest.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.search;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import junit.textui.TestRunner;
import org.apache.slide.common.Domain;
import org.apache.slide.search.ISearchToken;
import org.apache.slide.search.PropertyProvider;
import org.apache.slide.search.QueryScope;
import org.apache.slide.search.SearchException;
import org.apache.slide.search.basic.IBasicExpression;
import org.apache.slide.search.basic.IBasicExpressionFactory;
import org.apache.slide.store.tamino.Configuration;
import org.apache.slide.store.tamino.common.XGlobals;
import org.apache.slide.store.tamino.store.FakeStore;
import org.easymock.EasyMock;
import org.easymock.MockControl;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

/**
 * this one currently does not run, as internally the IBasicQuery is casted
 * to XBasicQueryImpl. This is legal, as within the XBasicQuery stuff only
 * XBasicQueryImpl objects may occur. So we should define an interface for that to
 * mock XBasicQueryImpl
 *
 * @author martin.wallmer@softwareag.com
 *
 * @version $Revision: 1.3 $
 */
public class XBasicExpressionFactoryTest extends TestCase {
    
    private MockControl ctrlQuery;
    private XBasicQuery mockQuery;
    
    private MockControl ctrlScope;
    private QueryScope  mockScope;
    
    private MockControl ctrlSearchToken;
    private ISearchToken  mockSearchToken;
    
    private MockControl ctrlPropertyProvider;
    private PropertyProvider mockPropertyProvider;
    
    //    private FakePropertyProvider propProv;
    
    private FakeStore store;
    
    private static final String collection = "searchtest";
    private static final String slidePath = "/search/music";
    //private ISlideAccessor store;
    
    private List compareTests  = new ArrayList();
    private List notCompareTests = new ArrayList();
    
    
    private static final String EQ1 = ""
        +           "<eq xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<displayname/>"
        +               "</prop>"
        +               "<literal>cathgirls.mp3</literal>"
        +           "</eq>";
    
    
    private static final String XEQ1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//nodeProperty[@name=\"displayname\" and @namespace=\"DAV:\" and "
        + "shadow=\"cathgirls.mp3\" and text()=\"cathgirls.mp3\"])]";
    
    private static final String LTE1 = ""
        +           "<lte xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<displayname/>"
        +               "</prop>"
        +               "<literal>cathgirls.mp3</literal>"
        +           "</lte>";
    
    private static final String XLTE1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//nodeProperty[@name=\"displayname\" and @namespace=\"DAV:\" and "
        + "shadow<=\"cathgirls.mp3\" and text()<=\"cathgirls.mp3\"])]";
    
    private static final String GTE1 = ""
        +           "<gte xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<displayname/>"
        +               "</prop>"
        +               "<literal>cathgirls.mp3</literal>"
        +           "</gte>";
    
    private static final String XGTE1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//nodeProperty[@name=\"displayname\" and @namespace=\"DAV:\" and "
        + "shadow>=\"cathgirls.mp3\" and text()>=\"cathgirls.mp3\"])]";
    
    private static final String LT1 = ""
        +           "<lt xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<displayname/>"
        +               "</prop>"
        +               "<literal>cathgirls.mp3</literal>"
        +           "</lt>";
    
    private static final String XLT1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//nodeProperty[@name=\"displayname\" and @namespace=\"DAV:\" and "
        + "shadow<=\"cathgirls.mp3\" and text()<\"cathgirls.mp3\"])]";
    
    private static final String GT1 = ""
        +           "<gt xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<getcontentlength/>"
        +               "</prop>"
        +               "<literal>1000</literal>"
        +           "</gt>";
    
    // eigentlich sollte die 1000 nicht in hochkomma stehen!!
    private static final String XGT1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//propertyList/D:getcontentlength [shadow>=1000 and text()>1000])]";
    
    
    private static final String ISDEFINED1 = ""
        +           "<isdefined xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<hugo/>"
        +               "</prop>"
        +           "</isdefined>";
    
    private static final String XISDEFINED1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//nodeProperty[@name=\"hugo\" and @namespace=\"DAV:\" ])]";
    
    private static final String ISDEFINED2 = ""
        +           "<isdefined xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<xdavContentId xmlns=\"http://namespaces.softwareag.com/tamino/webdav\"/>"
        +               "</prop>"
        +           "</isdefined>";
    
    private static final String XISDEFINED2 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//propertyList/xsv:xdavContentId)]";
    
    
    private static final String ISCOLLECTION1 = ""
        +           "<is-collection xmlns=\"DAV:\"/>";
    
    private static final String XISCOLLECTION1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//propertyList/D:resourcetype [shadow~=\"*collection*\"])]";
    
    private static final String ISPRINCIPAL1 = ""
        +           "<is-principal xmlns=\"http://jakarta.apache.org/slide/\"/>";
    
    private static final String XISPRINCIPAL1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//propertyList/D:resourcetype [shadow~=\"*principal*\"])]";
    
    
    private static final String PROPCONTAINS1 = ""
        +           "<x:propcontains xmlns:x=\"http://jakarta.apache.org/slide/\""
        +             " xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<displayname/>"
        +               "</prop>"
        +               "<literal>girls</literal>"
        +           "</x:propcontains>";
    
    private static final String XPROPCONTAINS1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//nodeProperty[@name=\"displayname\" and @namespace=\"DAV:\" and text()~=\"*girls*\"])]";
    
    private static final String N_EQ1 = ""
        +           "<not-eq xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<displayname/>"
        +               "</prop>"
        +               "<literal>cathgirls.mp3</literal>"
        +           "</not-eq>";
    
    private static final String XN_EQ1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//nodeProperty[@name=\"displayname\" and @namespace=\"DAV:\" and "
        + "text()!=\"cathgirls.mp3\"])]";
    
    
    private static final String N_LTE1 = ""
        +           "<not-lte xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<displayname/>"
        +               "</prop>"
        +               "<literal>cathgirls.mp3</literal>"
        +           "</not-lte>";
    
    private static final String XN_LTE1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//nodeProperty[@name=\"displayname\" and @namespace=\"DAV:\" and "
        + "shadow>=\"cathgirls.mp3\" and text()>\"cathgirls.mp3\"])]";
    
    private static final String N_GTE1 = ""
        +           "<not-gte xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<displayname/>"
        +               "</prop>"
        +               "<literal>cathgirls.mp3</literal>"
        +           "</not-gte>";
    
    private static final String XN_GTE1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//nodeProperty[@name=\"displayname\" and @namespace=\"DAV:\" and "
        + "shadow<=\"cathgirls.mp3\" and text()<\"cathgirls.mp3\"])]";
    
    private static final String N_LT1 = ""
        +           "<not-lt xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<displayname/>"
        +               "</prop>"
        +               "<literal>cathgirls.mp3</literal>"
        +           "</not-lt>";
    
    private static final String XN_LT1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//nodeProperty[@name=\"displayname\" and @namespace=\"DAV:\" and "
        + "shadow>=\"cathgirls.mp3\" and text()>=\"cathgirls.mp3\"])]";
    
    private static final String N_GT1 = ""
        +           "<not-gt xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<getcontentlength/>"
        +               "</prop>"
        +               "<literal>1000</literal>"
        +           "</not-gt>";
    
    // eigentlich sollte die 1000 nicht in hochkomma stehen!!
    private static final String XN_GT1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//propertyList/D:getcontentlength [shadow<=1000 and text()<=1000])]";
    
    private static final String N_ISDEFINED1 = ""
        +           "<not-isdefined xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<hugo/>"
        +               "</prop>"
        +           "</not-isdefined>";
    
    private static final String XN_ISDEFINED1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//nodeProperty[@name=\"hugo\" and @namespace=\"DAV:\" ])]";
    
    private static final String N_ISDEFINED2 = ""
        +           "<not-isdefined xmlns=\"DAV:\">"
        +               "<prop>"
        +                   "<xdavContentId xmlns=\"http://namespaces.softwareag.com/tamino/webdav\"/>"
        +               "</prop>"
        +           "</not-isdefined>";
    
    private static final String XN_ISDEFINED2 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(not (//propertyList/xsv:xdavContentId))]";
    
    
    private static final String N_ISCOLLECTION1 = ""
        +           "<not-is-collection xmlns=\"DAV:\"/>";
    
    private static final String XN_ISCOLLECTION1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//nodeProperty[@name=\"resourcetype\" and @namespace=\"DAV:\" and not "
        + "(shadow~=\"*collection*\")])]";
    
    
    
    private static final String N_ISPRINCIPAL1 = ""
        +           "<not-is-principal xmlns=\"http://jakarta.apache.org/slide/\"/>";
    
    private static final String XN_ISPRINCIPAL1 =
        "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
        + "@depth <= 3 and "
        + "(//propertyList/D:resourcetype [not (shadow~=\"*principal*\")])]";
    
    private static final String XPATH1 = ""
        +           "<x:xpath xmlns:x=\"http://namespaces.softwareag.com/tamino/webdav\""
        +             " xmlns=\"DAV:\">"
        +               "cd/artist/"
        +           "</x:xpath>";
    
    
    
    private static final String XXPATH1 = "cd/artist/";
    
    
    protected void setUp () throws Exception {
        super.setUp();
        Domain.setInitialized (true);
        store = new FakeStore(Configuration.get().namespace);
        
        Configuration conf = Configuration.get();
        
        store.setParameter (XGlobals.TAMINO_COLLECTION, collection);
        store.setParameter (XGlobals.TAMINO_DATABASE, conf.getTaminoDatabaseUrl());
        store.setParameter (XGlobals.TAMINO_BASE,     conf.getTaminoDatabaseUrl());
        
        ctrlQuery = EasyMock.controlFor (XBasicQuery.class);
        mockQuery = (XBasicQuery)ctrlQuery.getMock();
        
        ctrlScope = EasyMock.controlFor (QueryScope.class);
        mockScope = (QueryScope) ctrlScope.getMock();
        
        ctrlPropertyProvider = EasyMock.controlFor (PropertyProvider.class);
        mockPropertyProvider = (PropertyProvider) ctrlPropertyProvider.getMock();
        ctrlPropertyProvider.activate();
        
        mockScope.isCollection();
        ctrlScope.setReturnValue (true);
        mockScope.getHref();
        ctrlScope.setReturnValue (slidePath);
        mockScope.getDepth();
        ctrlScope.setReturnValue (Integer.MAX_VALUE);
        ctrlScope.activate();
        
        mockQuery.getStore();
        ctrlQuery.setReturnValue (store);
        mockQuery.getSlidePath();
        ctrlQuery.setReturnValue (slidePath);
        mockQuery.getScope ();
        ctrlQuery.setReturnValue (mockScope);
        mockQuery.getProtectedDepth();
        ctrlQuery.setReturnValue (1);
        mockQuery.getOrderBy();
        ctrlQuery.setReturnValue (null);
        ctrlQuery.activate ();
        
        // prepare compare tests
        addToList (EQ1, XEQ1, compareTests);
        addToList (GT1, XGT1, compareTests);
        addToList (GTE1, XGTE1, compareTests);
        addToList (LT1, XLT1, compareTests);
        addToList (LTE1, XLTE1, compareTests);
        addToList (ISDEFINED1, XISDEFINED1, compareTests);
        addToList (ISDEFINED2, XISDEFINED2, compareTests);
        addToList (ISCOLLECTION1, XISCOLLECTION1, compareTests);
        addToList (ISPRINCIPAL1, XISPRINCIPAL1, compareTests);
        addToList (PROPCONTAINS1, XPROPCONTAINS1, compareTests);
        addToList (N_EQ1, XN_EQ1, compareTests);
        addToList (N_GT1, XN_GT1, compareTests);
        addToList (N_GTE1, XN_GTE1, compareTests);
        addToList (N_LT1, XN_LT1, compareTests);
        addToList (N_LTE1, XN_LTE1, compareTests);
        addToList (N_ISPRINCIPAL1, XN_ISPRINCIPAL1, compareTests);
        addToList (N_ISDEFINED2, XN_ISDEFINED2, compareTests);
    }
    
    /**
     ** 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 XBasicExpressionFactoryTest (String testMethodName) {
        super (testMethodName);
    }
    
    public void testCompareExpressions () {
        IBasicExpressionFactory factory = new XBasicExpressionFactory ();
        
        try {
            factory.init (mockQuery, mockPropertyProvider);
            
            for (int i = 0; i < compareTests.size(); i++) {
                DaslXPath dx = (DaslXPath)compareTests.get(i);
                
                Element jdom = getElement (dx.dasl);
                IBasicExpression exp = factory.createExpression (jdom);
                assertTrue (exp instanceof XCompareExpression);
                
                // exp.execute();
                
                String queryString = ((XBasicExpression)exp).createQueryString (slidePath).trim();
                //                System.out.println("");
                //                System.out.println (dx.xPath);
                //                System.out.println (queryString);
                //                System.out.println("");
                
                assertEquals (i + ": ", dx.xPath, queryString);
                
            }
        }
        catch (SearchException e) {
            e.printStackTrace();
            fail (e.getMessage());
        }
    }
    
    public void testMergeExpression () {
        IBasicExpressionFactory factory = new XBasicExpressionFactory ();
        
        String XAND1 =
            "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
            + "@depth <= 3 and "
            + "((//nodeProperty[@name=\"displayname\" and @namespace=\"DAV:\" and "
            + "shadow=\"cathgirls.mp3\" and text()=\"cathgirls.mp3\"]) and "
            + "(//propertyList/xsv:xdavContentId))]";
        
        String XOR1 =
            "searchtest [(@uri=\"/search/music\" or @uri~=\"/search/music*\") and "
            + "@depth <= 3 and "
            + "(((//nodeProperty[@name=\"displayname\" and @namespace=\"DAV:\" and "
            + "shadow=\"cathgirls.mp3\" and text()=\"cathgirls.mp3\"]) and "
            + "(//propertyList/xsv:xdavContentId))"
            + " or (//nodeProperty[@name=\"displayname\" and @namespace=\"DAV:\" and "
            + "shadow<=\"cathgirls.mp3\" and text()<\"cathgirls.mp3\"]))]";
        
        Element eq1 = getElement (EQ1);
        Element isDef = getElement (ISDEFINED2);
        Element lt1 = getElement (LT1);
        
        try {
            factory.init (mockQuery, mockPropertyProvider);
            
            List expList = new ArrayList ();
            expList.add (factory.createExpression (eq1));
            expList.add (factory.createExpression (isDef));
            
            IBasicExpression andExpression =
                factory.createMergeExpression ("and", "DAV:", expList);
            
            String queryString = ((XBasicExpression)andExpression).createQueryString (slidePath).trim();
            //                        System.out.println ("");
            //                        System.out.println (XAND1);
            //                        System.out.println (queryString);
            //                        System.out.println ("");
            
            assertEquals (XAND1, queryString);
            
            expList = new ArrayList ();
            expList.add (andExpression);
            expList.add (factory.createExpression (lt1));
            
            IBasicExpression orExpression =
                factory.createMergeExpression ("or", "DAV:", expList);
            
            queryString =
                ((XBasicExpression)orExpression).createQueryString (slidePath).trim();
            
            //          System.out.println ("");
            //          System.out.println (XOR1);
            //          System.out.println (queryString);
            //          System.out.println ("");
            
            assertEquals (XOR1, queryString);
            
        }
        
        catch (SearchException e) {
            e.printStackTrace();
            fail (e.getMessage());
        }
        
    }
    
    
    /**
     commented out, as in XPathExpression the query is casted to XBasicQueryImpl,
     which is not covered by the mock object.
     */
    //    public void testXPathExpression () {
    //        IBasicExpressionFactory factory = new XBasicExpressionFactory ();
//
    //        try {
    //            factory.init (mockQuery, mockPropertyProvider);
    //            IBasicExpression exp = factory.createExpression (getElement(XPATH1));
    //            String queryString =
    //                ((XBasicExpression)exp).createQueryString (slidePath);
//
    //            System.out.println (queryString);
    //            assertEquals (XXPATH1, queryString);
    //        }
    //        catch (SearchException e) {
    //            e.printStackTrace();
    //            fail (e.getMessage());
    //        }
    //    }
    
    
    private void addToList (String dasl, String xPath, List list) {
        DaslXPath daslXPath = new DaslXPath (dasl, xPath);
        list.add (daslXPath);
    }
    
    private Element getElement (String xmlString) {
        SAXBuilder builder = new SAXBuilder ();
        Element elem = null;
        Document doc = null;
        try {
            doc = builder.build (new StringReader (xmlString));
            elem = doc.getRootElement();
        }
        
        catch (org.jdom.JDOMException e) {
            e.printStackTrace();
            fail (e.getMessage());
        }
        catch (IOException e) {
            e.printStackTrace();
            fail (e.getMessage());
        }
        
        return elem;
    }
    
    class DaslXPath {
        String dasl;
        String xPath;
        
        DaslXPath (String d, String x) {
            dasl = d;
            xPath = x;
        }
    }
    
    public static void main( String[] args ) {
        TestRunner.run( suite() );
    }
    public static Test suite() {
        return new TestSuite(XBasicExpressionFactoryTest.class);
    }
}


