/********************************************************************
 * COPYRIGHT: 
 * Copyright (c) 2001-2004, International Business Machines Corporation and
 * others. All Rights Reserved.
 ********************************************************************/
/************************************************************************
*   This test program is intended for testing error conditions of the 
*   transliterator APIs to make sure the exceptions are raised where
*   necessary.
*
*   Date        Name        Description
*   11/14/2001  hshih       Creation.
* 
************************************************************************/

#include "unicode/utypes.h"

#if !UCONFIG_NO_TRANSLITERATION

#include "ittrans.h"
#include "trnserr.h"
#include "unicode/utypes.h"
#include "unicode/translit.h"
#include "unicode/uniset.h"
#include "rbt.h"
#include "unicode/unifilt.h"
#include "cpdtrans.h"
#include "nultrans.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "unicode/rep.h"
#include "unicode/locid.h"

//---------------------------------------------
// runIndexedTest
//---------------------------------------------

void
TransliteratorErrorTest::runIndexedTest(int32_t index, UBool exec,
                                      const char* &name, char* /*par*/) {
    switch (index) {
        TESTCASE(0,TestTransliteratorErrors);
        TESTCASE(1, TestUnicodeSetErrors);
        TESTCASE(2, TestRBTErrors);
        //TESTCASE(3, TestUniToHexErrors);
        //TESTCASE(4, TestHexToUniErrors);
        // TODO: Add a subclass to test clone().
        default: name = ""; break;
    }
}


void TransliteratorErrorTest::TestTransliteratorErrors() {
    UnicodeString trans="Latin-Greek";
    UnicodeString bogusID="LATINGREEK-GREEKLATIN";
    UnicodeString newID="Bogus-Latin";
    UnicodeString newIDRules="zzz > Z; f <> ph";
    UnicodeString bogusRules="a } [b-g m-p ";
    UParseError parseError;
    UErrorCode status = U_ZERO_ERROR;
    UnicodeString testString="A quick fox jumped over the lazy dog.";
    UnicodeString insertString="cats and dogs";
    int32_t stoppedAt = 0, len;
    UTransPosition pos;

    Transliterator* t= Transliterator::createInstance(trans, UTRANS_FORWARD, parseError, status);
    if(t==0 || U_FAILURE(status)){
        errln("FAIL: construction of Latin-Greek");
        return;
    }
    pos.contextLimit = 0;
    pos.contextStart = 0;
    pos.limit = 0;
    pos.start = 0;
    len = testString.length();
    stoppedAt = t->transliterate(testString, 0, 100);
    if (stoppedAt != -1) {
        errln("FAIL: Out of bounds check failed (1).");
    } else if (testString.length() != len) {
        testString="A quick fox jumped over the lazy dog.";        
        errln("FAIL: Transliterate fails and the target string was modified.");
    }
    stoppedAt = t->transliterate(testString, 100, testString.length()-1);
    if (stoppedAt != -1)
        errln("FAIL: Out of bounds check failed (2).");
    else if (testString.length() != len) {
        testString="A quick fox jumped over the lazy dog.";        
        errln("FAIL: Transliterate fails and the target string was modified.");
    }
    pos.start = 100;
    pos.limit = testString.length();
    t->transliterate(testString, pos, status);
    if (U_SUCCESS(status)) {
        errln("FAIL: Start offset is out of bounds, error not reported.\n");
    }
    status = U_ZERO_ERROR;
    pos.limit = 100;
    pos.start = 0;
    t->transliterate(testString, pos, status);
    if (U_SUCCESS(status)) {
        errln("FAIL: Limit offset is out of bounds, error not reported.\n");
    }
    status = U_ZERO_ERROR;
    len = pos.contextLimit = testString.length();
    pos.contextStart = 0;
    pos.limit = len - 1;
    pos.start = 5;
    t->transliterate(testString, pos, insertString, status);
    if (len == pos.limit) {
        errln("FAIL: Test insertion with string: the transliteration position limit didn't change as expected.");
        if (U_SUCCESS(status)) {
            errln("FAIL: Error code wasn't set either.");
        }
    }
    status = U_ZERO_ERROR;
    pos.contextStart = 0;
    pos.contextLimit = testString.length();
    pos.limit = testString.length() -1;
    pos.start = 5;
    t->transliterate(testString, pos, (UChar32)0x0061, status);
    if (len == pos.limit) {
        errln("FAIL: Test insertion with character: the transliteration position limit didn't change as expected.");
        if (U_SUCCESS(status)) {
            errln("FAIL: Error code wasn't set either.");
        }
    }
    status = U_ZERO_ERROR;
    len = pos.limit = testString.length();
    pos.contextStart = 0;
    pos.contextLimit = testString.length() - 1;
    pos.start = 5;
    t->transliterate(testString, pos, insertString, status);
    if (U_SUCCESS(status)) {
        errln("FAIL: Out of bounds check failed (3).");
        if (testString.length() != len)
            errln("FAIL: The input string was modified though the offsets were out of bounds.");
    }
    Transliterator* t1= Transliterator::createInstance(bogusID, UTRANS_FORWARD, parseError, status);
    if(t1!=0 || U_SUCCESS(status)){
        delete t1;
        errln("FAIL: construction of bogus ID \"LATINGREEK-GREEKLATIN\"");
    } else {
        delete t1;
    }
    status = U_ZERO_ERROR;
    Transliterator* t2 = new RuleBasedTransliterator(newID, newIDRules, UTRANS_FORWARD, status);
    if (U_SUCCESS(status)) {
        Transliterator* t3 = t2->createInverse(status);
        if (U_SUCCESS(status)) {
            delete t3;
            errln("FAIL: The newID transliterator was not registered so createInverse should fail.");
        } else {
            delete t3;
        }
    }
    status = U_ZERO_ERROR;
    Transliterator* t4 = Transliterator::createFromRules(newID, bogusRules, UTRANS_FORWARD, parseError, status);
    if (t4 != NULL || U_SUCCESS(status)) {
        errln("FAIL: The rules is malformed but error was not reported.");
        if (parseError.offset != -1) {
            errln("FAIL: The parse error offset isn't set correctly when fails.");
        } else if (parseError.postContext[0] == 0 || parseError.preContext[0] == 0) {
            errln("FAIL: The parse error pre/post context isn't reset properly.");
        }
        delete t4;
    }    
    delete t;
    delete t2;
}

void TransliteratorErrorTest::TestUnicodeSetErrors() {
    UnicodeString badPattern="[[:L:]-[0x0300-0x0400]";
    UnicodeSet set;
    UErrorCode status = U_ZERO_ERROR;
    UnicodeString result;

    if (!set.isEmpty()) {
        errln("FAIL: The default ctor of UnicodeSet created a non-empty object.");
    }
    set.applyPattern(badPattern, status);
    if (U_SUCCESS(status)) {
        errln("FAIL: Applied a bad pattern to the UnicodeSet object okay.");
    }
    status = U_ZERO_ERROR;
    UnicodeSet *set1 = new UnicodeSet(badPattern, status);
    if (U_SUCCESS(status)) {
        errln("FAIL: Created a UnicodeSet based on bad patterns.");
    }
    delete set1;
}

//void TransliteratorErrorTest::TestUniToHexErrors() {
//    UErrorCode status = U_ZERO_ERROR;
//    Transliterator *t = new UnicodeToHexTransliterator("", TRUE, NULL, status);
//    if (U_SUCCESS(status)) {
//        errln("FAIL: Created a UnicodeToHexTransliterator with an empty pattern.");
//    }
//    delete t;
//
//    status = U_ZERO_ERROR;
//    t = new UnicodeToHexTransliterator("\\x", TRUE, NULL, status);
//    if (U_SUCCESS(status)) {
//        errln("FAIL: Created a UnicodeToHexTransliterator with a bad pattern.");
//    }
//    delete t;
//
//    status = U_ZERO_ERROR;
//    t = new UnicodeToHexTransliterator();
//    ((UnicodeToHexTransliterator*)t)->applyPattern("\\x", status);
//    if (U_SUCCESS(status)) {
//        errln("FAIL: UnicodeToHexTransliterator::applyPattern succeeded with a bad pattern.");
//    }
//    delete t;
//}

void TransliteratorErrorTest::TestRBTErrors() {

    UnicodeString rules="ab>y";
    UnicodeString id="MyRandom-YReverse";
    UnicodeString goodPattern="[[:L:]&[\\u0000-\\uFFFF]]"; /* all BMP letters */
    UErrorCode status = U_ZERO_ERROR;
    UParseError parseErr;
    UnicodeSet *set = new UnicodeSet(goodPattern, status);
    if (U_FAILURE(status)) {
        errln("FAIL: Was not able to create a good UnicodeSet based on valid patterns.");
        return;
    }
    RuleBasedTransliterator *t = new RuleBasedTransliterator(id, rules, UTRANS_REVERSE, set, parseErr, status);
    if (U_FAILURE(status)) {
        errln("FAIL: Was not able to create a good RBT to test registration.");
        delete set;
        return;
    }
    Transliterator::registerInstance(t);
    Transliterator::unregister(id);
    status = U_ZERO_ERROR;
    Transliterator* t1= Transliterator::createInstance(id, UTRANS_REVERSE, parseErr, status);
    if(U_SUCCESS(status)){
        delete t1;
        errln("FAIL: construction of unregistered ID failed.");
    } 
}

//void TransliteratorErrorTest::TestHexToUniErrors() {
//    UErrorCode status = U_ZERO_ERROR;
//    Transliterator *t = new HexToUnicodeTransliterator("", NULL, status);
//    if (U_FAILURE(status)) {
//        errln("FAIL: Could not create a HexToUnicodeTransliterator with an empty pattern.");
//    }
//    delete t;
//    status = U_ZERO_ERROR;
//    t = new HexToUnicodeTransliterator("\\x", NULL, status);
//    if (U_SUCCESS(status)) {
//        errln("FAIL: Created a HexToUnicodeTransliterator with a bad pattern.");
//    }
//    delete t;
//    status = U_ZERO_ERROR;
//    t = new HexToUnicodeTransliterator();
//    ((HexToUnicodeTransliterator*)t)->applyPattern("\\x", status);
//    if (U_SUCCESS(status)) {
//        errln("FAIL: HexToUnicodeTransliterator::applyPattern succeeded with a bad pattern.");
//    }
//    delete t;
//}

#endif /* #if !UCONFIG_NO_TRANSLITERATION */
