// Copyright 2008-2014 severally by the contributors
//
// 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 net.sf.practicalxml.xpath;

import java.util.List;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

import net.sf.practicalxml.AbstractTestCase;
import net.sf.practicalxml.DomUtil;
import net.sf.practicalxml.ParseUtil;


public class TestAbstractStringFunction
extends AbstractTestCase
{
//----------------------------------------------------------------------------
//  Support code
//----------------------------------------------------------------------------

    private Document emptyDom = DomUtil.newDocument();


    /**
     *  An implementation of AbstractStringFunction that simply returns the
     *  string value of its first argument.
     */
    private static class IdentityStringFunction
    extends AbstractStringFunction
    {
        public IdentityStringFunction()
        {
            super("urn:net.sf.practicalxml", "myfunc");
        }

        @Override
        @SuppressWarnings("rawtypes")
        public Object evaluate(String value, List args)
        {
            return value;
        }
    }


    /**
     *  Validates that string conversion behaves identically to the built-in
     *  <code>string()</code> function, by constructing and evaluating XPath
     *  expressions using both.
     *
     *  @param  expr    An XPath expression used as the argument to both the
     *                  test function and <code>string()</code>.
     *  @param  context Context used for evaluating both expressions.
     */
    private void assertStringConversion(String expr, Node context)
    {
        XPathWrapper builtIn = new XPathWrapper("string(" + expr + ")");
        XPathWrapper custom  = new XPathWrapper("fn:myfunc(" + expr + ")")
                               .bindFunction(new IdentityStringFunction(), "fn");

        assertEquals(builtIn.evaluateAsString(context), custom.evaluateAsString(context));
    }


//----------------------------------------------------------------------------
//  Test cases
//----------------------------------------------------------------------------

    public void testConversionOfLiteralString() throws Exception
    {
        assertStringConversion("'foo'", emptyDom);
    }


    public void testConversionOfNumber() throws Exception
    {
        assertStringConversion("number(123)", emptyDom);
        assertStringConversion("number(123.456)", emptyDom);
        assertStringConversion("number(1 div 0)", emptyDom);
        assertStringConversion("number(-1 div 0)", emptyDom);
        assertStringConversion("number(0 div 0)", emptyDom);
    }


    public void testConversionOfBoolean() throws Exception
    {
        assertStringConversion("true()", emptyDom);
        assertStringConversion("false()", emptyDom);
    }


    public void testConversionOfNodeList() throws Exception
    {
        Document dom = ParseUtil.parse(
                "<root>"
                + "<foo>argle</foo>"
                + "<bar>bargle<baz>bazzle</baz></bar>"
                + "</root>");

        assertStringConversion("/root/foo",         dom);
        assertStringConversion("/root/foo/bar",     dom);
        assertStringConversion("/root/foo/bar/baz", dom);
        assertStringConversion("/nonesuch",         dom);
    }
}
