// fts_element_iterator_test.cpp
/**
*    Copyright (C) 2014 MongoDB Inc.
*
*    This program is free software: you can redistribute it and/or  modify
*    it under the terms of the GNU Affero General Public License, version 3,
*    as published by the Free Software Foundation.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
*    As a special exception, the copyright holders give permission to link the
*    code of portions of this program with the OpenSSL library under certain
*    conditions as described in each individual source file and distribute
*    linked combinations including the program with the OpenSSL library. You
*    must comply with the GNU Affero General Public License in all respects for
*    all of the code used other than as permitted herein. If you modify file(s)
*    with this exception, you may extend this exception to your version of the
*    file(s), but you are not obligated to do so. If you do not wish to do so,
*    delete this exception statement from your version. If you delete this
*    exception statement from all source files in the program, then also delete
*    it in the license file.
*/

#include "mongo/pch.h"

#include "mongo/db/fts/fts_element_iterator.h"
#include "mongo/db/json.h"
#include "mongo/unittest/unittest.h"

namespace mongo {
    namespace fts {

        TEST( FTSElementIterator, Test1 ) {

            BSONObj obj = fromjson(
                "{ b : \"walking\","
                "  c : { e: \"walked\" },"
                "  d : \"walker\""
                "  }" );

            BSONObj indexSpec = fromjson(
                "{ key : { a : \"text\" }, weights : { b : 10, d : 5 } }" );

            FTSSpec spec( FTSSpec::fixSpec( indexSpec ) );
            Weights::const_iterator itt = spec.weights().begin();
            ASSERT( itt != spec.weights().end() );
            ASSERT_EQUALS( "a", itt->first );
            ASSERT_EQUALS(  1, itt->second );
            ++itt;
            ASSERT( itt != spec.weights().end() );
            ASSERT_EQUALS( "b", itt->first );
            ASSERT_EQUALS( 10, itt->second );
            ++itt;
            ASSERT( itt != spec.weights().end() );
            ASSERT_EQUALS( "d", itt->first );
            ASSERT_EQUALS(  5, itt->second );
            ++itt;

            FTSElementIterator it( spec, obj );

            ASSERT( it.more() );
            FTSIteratorValue val = it.next();
            ASSERT_EQUALS( "walking", string(val._text) );
            ASSERT_EQUALS( "english", val._language->str() );
            ASSERT_EQUALS( 10, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "walker", string(val._text) );
            ASSERT_EQUALS( "english", val._language->str() );
            ASSERT_EQUALS( 5, val._weight );
        }

        // Multi-language : test
        TEST( FTSElementIterator, Test2 ) {

            BSONObj obj = fromjson(
                "{ a :"
                "  { b :"
                "    [ { c : \"walked\", language : \"english\" },"
                "      { c : \"camminato\", language : \"italian\" },"
                "      { c : \"ging\", language : \"german\" } ]"
                "   },"
                "  d : \"Feliz Año Nuevo!\","
                "  language : \"spanish\""
                " }" );

            BSONObj indexSpec = fromjson(
                "{ key : { \"a.b.c\" : \"text\", d : \"text\" } }" );

            FTSSpec spec( FTSSpec::fixSpec( indexSpec ) );

            FTSElementIterator it( spec, obj );

            ASSERT( it.more() );
            FTSIteratorValue val = it.next();
            ASSERT_EQUALS( "walked", string(val._text) );
            ASSERT_EQUALS( "english", val._language->str() );
            ASSERT_EQUALS( 1, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "camminato", string(val._text) );
            ASSERT_EQUALS( "italian", val._language->str() );
            ASSERT_EQUALS( 1, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "ging", string(val._text) );
            ASSERT_EQUALS( "german", val._language->str() );
            ASSERT_EQUALS( 1, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "Feliz Año Nuevo!", string(val._text) );
            ASSERT_EQUALS( "spanish", val._language->str() );
            ASSERT_EQUALS( 1, val._weight );
        }

        // Multi-language : test nested stemming per sub-document
        TEST( FTSElementIterator, Test3 ) {

            BSONObj obj = fromjson(
                "{ language : \"english\","
                "  a :"
                "  { language : \"danish\","
                "    b :"
                "    [ { c : \"foredrag\" },"
                "      { c : \"foredragsholder\" },"
                "      { c : \"lector\" } ]"
                "  }"
                "}" );

            BSONObj indexSpec = fromjson(
                "{ key : { a : \"text\", \"a.b.c\" : \"text\" }, weights : { \"a.b.c\" : 5 } }" );

            FTSSpec spec( FTSSpec::fixSpec( indexSpec ) );
            Weights::const_iterator itt = spec.weights().begin();
            ASSERT( itt != spec.weights().end() );
            ASSERT_EQUALS( "a", itt->first );
            ASSERT_EQUALS(  1, itt->second );
            ++itt;
            ASSERT( itt != spec.weights().end() );
            ASSERT_EQUALS( "a.b.c", itt->first );
            ASSERT_EQUALS(  5, itt->second );

            FTSElementIterator it( spec, obj );

            ASSERT( it.more() );
            FTSIteratorValue val = it.next();
            ASSERT_EQUALS( "foredrag", string(val._text) );
            ASSERT_EQUALS( "danish", val._language->str() );
            ASSERT_EQUALS( 5, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "foredragsholder", string(val._text) );
            ASSERT_EQUALS( "danish", val._language->str() );
            ASSERT_EQUALS( 5, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "lector", string(val._text) );
            ASSERT_EQUALS( "danish", val._language->str() );
            ASSERT_EQUALS( 5, val._weight );

        }

        // Multi-language : test nested arrays
        TEST( FTSElementIterator, Test4 ) {

            BSONObj obj = fromjson(
                "{ language : \"english\","
                "  a : ["
                "  { language : \"danish\","
                "    b :"
                "    [ { c : [\"foredrag\"] },"
                "      { c : [\"foredragsholder\"] },"
                "      { c : [\"lector\"] } ]"
                "  } ]"
                "}" );

            BSONObj indexSpec = fromjson(
                "{ key : { \"a.b.c\" : \"text\" }, weights : { \"a.b.c\" : 5 } }" );

            FTSSpec spec( FTSSpec::fixSpec( indexSpec ) );
            FTSElementIterator it( spec, obj );

            ASSERT( it.more() );
            FTSIteratorValue val = it.next();
            ASSERT_EQUALS( "foredrag", string(val._text) );
            ASSERT_EQUALS( "danish", val._language->str() );
            ASSERT_EQUALS( 5, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "foredragsholder", string(val._text) );
            ASSERT_EQUALS( "danish", val._language->str() );
            ASSERT_EQUALS( 5, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "lector", string(val._text) );
            ASSERT_EQUALS( "danish", val._language->str() );
            ASSERT_EQUALS( 5, val._weight );

        }

        // Multi-language : test wildcard spec
        TEST( FTSElementIterator, Test5 ) {

            BSONObj obj = fromjson(
                "{ language : \"english\","
                "  b : \"these boots were made for walking\","
                "  c : { e: \"I walked half way to the market before seeing the sunrise\" },"
                "  d : "
                "  { language : \"danish\","
                "    e :"
                "    [ { f : \"foredrag\", g : 12 },"
                "      { f : \"foredragsholder\", g : 13 },"
                "      { f : \"lector\", g : 14 } ]"
                "  }"
                "}" );

            BSONObj indexSpec = fromjson(
                "{ key : { a : \"text\" }, weights : { b : 20, c : 10, \"d.e.f\" : 5 } }" );

            FTSSpec spec( FTSSpec::fixSpec( indexSpec ) );
            FTSElementIterator it( spec, obj );

            ASSERT( it.more() );
            FTSIteratorValue val = it.next();
            ASSERT_EQUALS( "these boots were made for walking", string(val._text) );
            ASSERT_EQUALS( "english", val._language->str() );
            ASSERT_EQUALS( 20, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "foredrag", string(val._text) );
            ASSERT_EQUALS( "danish", val._language->str() );
            ASSERT_EQUALS( 5, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "foredragsholder", string(val._text) );
            ASSERT_EQUALS( "danish", val._language->str() );
            ASSERT_EQUALS( 5, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "lector", string(val._text) );
            ASSERT_EQUALS( "danish", val._language->str() );
            ASSERT_EQUALS( 5, val._weight );
        }

        // Multi-language : test wildcard spec
        TEST( FTSElementIterator, Test6 ) {

            BSONObj obj = fromjson(
                "{ language : \"english\","
                "  b : \"these boots were made for walking\","
                "  c : { e: \"I walked half way to the market before seeing the sunrise\" },"
                "  d : "
                "  { language : \"danish\","
                "    e :"
                "    [ { f : \"foredrag\", g : 12 },"
                "      { f : \"foredragsholder\", g : 13 },"
                "      { f : \"lector\", g : 14 } ]"
                "  }"
                "}" );

            BSONObj indexSpec = fromjson(
                "{ key : { a : \"text\" }, weights : { b : 20, c : 10, \"d.e.f\" : 5 } }" );

            FTSSpec spec( FTSSpec::fixSpec( indexSpec ) );
            FTSElementIterator it( spec, obj );

            ASSERT( it.more() );
            FTSIteratorValue val = it.next();
            ASSERT_EQUALS( "these boots were made for walking", string(val._text) );
            ASSERT_EQUALS( "english", val._language->str() );
            ASSERT_EQUALS( 20, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "foredrag", string(val._text) );
            ASSERT_EQUALS( "danish", val._language->str() );
            ASSERT_EQUALS( 5, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "foredragsholder", string(val._text) );
            ASSERT_EQUALS( "danish", val._language->str() );
            ASSERT_EQUALS( 5, val._weight );

            ASSERT( it.more() );
            val = it.next();
            ASSERT_EQUALS( "lector", string(val._text) );
            ASSERT_EQUALS( "danish", val._language->str() );
            ASSERT_EQUALS( 5, val._weight );
        }
    }
}

