// test_CSV.cpp (C) 2008 adolfo@di-mare.com

/** \file  test_CSV.cpp
    \brief Test ==> \c CSV.

    \author Adolfo Di Mare <adolfo@di-mare.com>
    \date   2008.

    \author A11788 Jose David Hine Gomez <david@hine.tk>
    \author A24444 Cristopher Rojas Salas <crisrojassalas@gmail.com>
    \author A56254 Carlos Jose Watson Morua <carlos.watson@yahoo.com>
    \author A61166 Adrian Ignacio Campos Oviedo <flippercallcampos@yahoo.com>
    \author A61196 Tabare Capitan Jimenez <tcjucrecci@gmail.com>
    \author A71569 Sergio Esteban Castillo Segura <scmaverick2002@yahoo.com>
    \author A73869 Pablo Ignacio Matamoros Sanchez <pollmts@gmail.com>
    \author A74668 Erick Abdiel Orestes Chaves <erborc06@yahoo.com>
    \author A76944 Alexander Vega Sanou <a_vega_sanou@hotmail.com>
*/

#include "BUnit.h"
#include "CSV_line.h"

#define C_CSV // truco para que compile "CSV.c"

/// Test ==> \c CSV.
class test_CSV : public TestCase {
public:
    test_CSV() {} ///< Constructor.
    bool run(); ///< Execute.
private:
    void test_setData();
    void test_op_data();
    void test_trim();
    void test_trimCSV();
    void test_chop();
    void test_istringstream();
    void test_setQuotedCSV();
    void test_getNextCSV();
//  void test_rebuildDquote();
    #ifdef C_CSV
        void test_trim_C();
        void test_chop_C();
    #endif
};

/// Efectúa las pruebas.
bool test_CSV::run() {
    test_setData();
    test_op_data();
    test_trim();
    test_trimCSV();
    test_chop();
    test_istringstream();
    test_setQuotedCSV();
    test_getNextCSV();
//  test_rebuildDquote();
    #ifdef C_CSV
        test_trim_C();
        test_chop_C();
    #endif
    return wasSuccessful();
}

#include <iostream> // cout
#include <sstream>  // basic_istringstream<>

/// Cantidad de elementos del vector \c V[].
///  - DIM() no se puede implementar con plantillas...
#define DIM(V) (sizeof(V) / sizeof(*V)) // *V == *(V+0) == V[0]

/// Test ==> \c setData().
void test_CSV::test_setData() {
    {{ // test::setData()
        CSV_line csv; //  012 3 ...4. .......5.
        //            // [,,a,b,"c,d","e f ""g"\r\n]
        csv.setData( ",,a,b,\"c,d\",\"e f \"\"g\"\r\n" );
        assertTrue( csv[0] == ""        ); // []
        assertTrue( csv[1] == ""        ); // []
        assertTrue( csv[2] == "a"       ); // [a]
        assertTrue( csv[3] == "b"       ); // [b]
        assertTrue( csv[4] == "c,d"     ); // [c,d]
        assertTrue( csv[5] == "e f \"g" ); // [e f "g]
        assertTrue( csv.size() == 6 );
    }}
    if (true) {
        char* t[13]; std::string str;
        //  0   1  .2 ..3. ..4  ..5.. 6 ..7 ..8.. 9. ...10.  ...11.   .12
        // ",",""," ",  "", "" , " " ,6,  7,  8  ,9"," \r, ",",11,","x\r\n"
        t[0] = "\",\"";             t[ 6] = "6";
        t[1] = "\"\"";              t[ 7] = "  7";
        t[2] = "\" \"";             t[ 8] = "  8  ";
        t[3] = "  \"\"";            t[ 9] = "9\"";
        t[4] = " \"\" ";            t[10] = "\" \r, \"";
        t[5] = " \" \" ";           t[11] = "\",11,\"";
                                    t[12] = "x\r\n";
        for (int i=0; i<12; ++i) {
            str += t[i];
            str += ',';
        }
        str += t[12];

        CSV_line csv; csv.setData( str.data() , str.length() );
        assertTrue( csv.size() == 13 );

        assertTrue( csv[ 0] == "," );
        assertTrue( csv[ 1] == "" );
        assertTrue( csv[ 2] == " " );
        for (int i=3; i<=9; ++i) {
            assertTrue_Msg( "t["+toString(i)+"] == ["+t[i]+"] ==> ["+csv[i]+']', t[i] == csv[i] );
        }
        assertTrue( csv[10] == " \r, " );
        assertTrue( csv[11] == ",11,"  );
        assertTrue( csv[12] != "x\r\n" );        assertTrue( csv[12] == "x" );
    }
    {   using namespace std;
        string s; s += '"'; s += '"';       // s contiene 2 comillas: ""
        assertTrue( s == string("\"\"") );  // así es cómo se hace
        assertTrue( "" == string("""") );   // """"  ==> "" "" ==> "" (concatenación de nulas)
        assertTrue( string("\"\"") != """" ); // """" es la hilera nula
    //  std::cout << '[' << """" << ']' << std::endl;   // graba []
    }
    if (false) { // código viejo usado para ver qué está pasando
        char* t[13]; std::string str; CSV_line csv; // left-over code
        std::cout << std::endl << '[' << str << ']' << std::endl;
        std::cout << "csv.size() == " << unsigned(csv.size()) << std::endl;
        for (size_t i=0; i<csv.size(); ++i) {
            std::cout << "csv[" << unsigned(i) << "] == [" << csv[i] << ']' << std::endl;
        }
        for (size_t i=0; i<csv.size(); ++i) {
            std::cout << "csv[" << unsigned(i) << "] == [" << csv[i] << ']';
            std::string s = csv[i]; trimCSV( s );
            std::cout << "  ==> [" << s << ']' << std::endl;
        }
        for (int i=0; i<9; ++i) {
            assertTrue_Msg( "t["+toString(i)+"]["+t[i]+"] == ["+csv[i]+']', t[i] == csv[i] );
        }
        { int i=0; std::cout << __LINE__ << " csv[" << i << "] == [" << csv[i] << ']' << std::endl; }
    }
    {   // Las comillas de Pipino Cuevas <pipino@cuevas.com>
        std::string res;
        setQuotedCSV(res,"2");       assertTrue(res == "2" );
        setQuotedCSV(res,"4,5");     assertTrue(res == "\"4,5\"" );

        setQuotedCSV( res, "," );    assertTrue(res == "\",\"");   // [","]
        setQuotedCSV( res,  "2" );   assertTrue(res == "2");       // [2]
        setQuotedCSV( res,  "" );    assertTrue(res == "");        // []
        setQuotedCSV( res, "4,5" );  assertTrue(res == "\"4,5\""); // ["4,5"]
    }
    {   //             [," ... "" "3x,]
        CSV_line csv( ",\" ... \"\" \"3x,list"  );
        assertTrue( csv.size() == 3 );
        assertTrue( csv[0] == "" );
        assertTrue( csv[1] == "\" ... \"\" \"3x" );
        assertTrue( csv[2] == "list" );
    }
    {
        CSV_line csv( ",\".\r\n\""  );
        assertTrue( csv.size() == 2 );
        assertTrue( csv[0] == "" );
        assertTrue( csv[1] == ".\r\n" );
    }
    {   // 0," ,,\r\n .. ",",,\r\n"",",123\r\n
        // 0 ...........1. .........2. ..3\r\n
        CSV_line csv; char * t[4]; std::string str;
        t[0] = "0";                // [0]
        t[1] = "\" ,,\r\n .. \"";  // [" ,,\r\n .. "];
        t[2] = "\",,\r\n\"\",\"";  // [",,\r\n"","] ==> [,,\r\n",]
        t[3] = "123\r\n";          // [123]
        for (int i=0; i<=2; ++i) {
            str += t[i];
            str += ',';
        }
        str += t[3];

        csv.setData( str.data() , str.length() );
        assertTrue( csv.size() == 4 );    assertTrue( csv.size() != 5 );
        assertTrue( csv[0] == "0"           );
        assertTrue( csv[1] == " ,,\r\n .. " );
        assertTrue( csv[2] == ",,\r\n\","   ); //  ==> [,,\r\n\",]
        assertTrue( csv[3] == "123"         );
        assertTrue( csv[3] != "123\r\n"     );        assertTrue( csv[3] != "123\r"     );
    }
    {
        CSV_line csv( "123\r\n" ); // [123\r\n ]
        assertTrue( csv[0] == "123"         );
        assertTrue( csv[0] != "123\r\n"     );        assertTrue( csv[0] != "123\r"     );
    }
    {
        CSV_line csv( ", \" 3rd\"  \r\n" );    // [, " 3rd"  \r\n]
        assertTrue( csv[0] == ""     );
        assertTrue( csv[1] == " \" 3rd\"  "  ); // [ " 3rd"  ]
        std::string copy = csv[1];
        trimCSV( copy );
        assertTrue( copy == " 3rd" );         // [3rd]
    }
    if (false) { // http://www.di-mare.com/adolfo/cursos/2008-1/p2-ea-3.htm
        const char * in[11]; const char * out[11];
        in[ 0] = "\"zero\"";              out[ 0] = "zero";
        in[ 1] = ",  \"if \"\" 1\" ";     out[ 1] = "  \"if \"\" 1\" ";
        in[ 2] = ", ";                    out[ 2] = " ";
        in[ 3] = ", \" 3xt\"  \r\n";      out[ 3] = " \" 3xt\"  ";
        in[ 4] = ",\"png\"\"\n\"\"\n";    out[ 4] = "png\"\n\"";
        in[ 5] = ",12345";                out[ 5] = "12345";
        in[ 6] = ",\"\"\r\n";             out[ 6] = "\"\"";
        in[ 7] = ",12\r666\r\n";          out[ 7] = "12\r666";
        in[ 8] = ",12\r\n";               out[ 8] = "12";
        in[ 9] = ",\"con blanco\"";       out[ 9] = "con blanco";
        in[10] = ",\"con,coma\"";         out[10] = "con,coma";

        std::string str;
        for (int i=0; i<=10; ++i) {
            str += in[i];
        }

        {
            std::vector<std::string> VEC;
            VEC.clear();          //
            std::string csv;
            bool eol_CIN = false; // stop when the end of line is reached
            std::istringstream ist( str , std::ios::binary );
            while ( /* ! eol_CIN && */ ! ist.fail() ) { // ! ist.eof() pitfall!
                eol_CIN = getNextCSV( csv, ist );
                VEC.push_back( csv );
            }
            //  Using std::ios::binary ensures that no CR+LF chars are discarded
            for (int i=0; i<=10; ++i) {
                assertTrue_Msg( std::string()+in[i]+" ==> "+out[i] , VEC[i]==out[i] );
            }
        }
        return;
    }
    {   // A11788
        CSV_line csv( "\"\"\"n\"" ); // ["""n"]
        assertTrue( csv[0] == "\"n" );  // ["n]
        assertTrue( csv.size() == 1 );
    }
    {   // A24444-A71569
        const int N_COUT = 0; // Cantidad de valores de csv[] grabados en cout
        std::string s, str;
        //     0  1       2        3            4   5 6
        //    [,"\n","pa""pa","ce\nro",  "el "" 1" , ,\n]
        str = ",\"\n\",\"pa\"\"pa\",\"ce\nro\",  \"el \"\" 1\" , ,\n";
        CSV_line csv; csv.setData( str.data() ); {
            assertTrue( csv[0] == "" );
            assertTrue( csv[1] == "\n" );
            assertTrue( csv[2] == "pa\"pa" );
            assertTrue( csv[3] == "ce\nro" );
            assertTrue( csv[4] == "  \"el \"\" 1\" " );
            assertTrue( csv[5] == " " );
            assertTrue( csv[6] == "" );
            assertTrue( csv.size() == 7 );
            for ( int i=0; i<csv.size()*N_COUT; ++i ) {
                std::cout << "csv[" << i << "] == [" << csv[i] << ']' << std::endl;
            }
        }
        //     0  1     2       3
        //    [,"\r","pato","perro"\r\n]
        str = ",\"\r\",\"pato\",\"perro\"\r\n";
        csv.setData( str.data() ); {
            assertTrue( csv[0] == "" );
            assertTrue( csv[1] == "\r" );
            assertTrue( csv[2] == "pato");
            assertTrue( csv[3] == "perro");
            assertTrue( csv[3] != "\"perro\"\n");  assertTrue( csv[3] != "\"perro\"\r\n");
            assertTrue( csv.size() == 4 );
            for ( int i=0; i<csv.size()*N_COUT; ++i ) {
                std::cout << "csv[" << i << "] == [" << csv[i] << ']' << std::endl;
            }
        }
        str = "perro\n,pato\n";
        csv.setData( str.data() ); {
            assertTrue( csv[0] == "perro" );      assertTrue( csv[0] != "perro\n" );
            assertTrue( csv.size() == 1 );
        //  assertTrue( csv[1] == ""    );        // BOOM !!!
        //  assertTrue( csv[1] != "pato");        assertTrue( csv[1] != "pato\n" );
            for ( int i=0; i<csv.size()*N_COUT; ++i ) {
                std::cout << "csv[" << i << "] == [" << csv[i] << ']' << std::endl;
            }
        }
    }
    {   // A56254
        CSV_line csv;
        char *ch1 = "a";
        char *ch2 = ",";
        char *ch3 = "\"2,3\"";
        char *ch4 = "\n";

        csv.setData(ch1,1); assertTrue(csv[0] == "a");
        csv.setData(ch2,1); assertTrue(csv[1] == "");
        csv.setData(ch3,5); assertTrue(csv[0] == "2,3");
        csv.setData(ch4,1); assertTrue(csv[0] == "");
    }
    {   // A61196-A76944
        CSV_line csv;
        csv.setData(","); assertTrue( csv[0] == "");

        csv.setData("\r\n"); {
            assertTrue( csv[0] == "");
            assertTrue( csv.size()== 1 );
        }

        csv.setData("0,1,2,\"\"\n"); { // [0,1,2,""\n]
            assertTrue( csv[0] == "0");
            assertTrue( csv[1] == "1");
            assertTrue( csv[2] == "2");
            assertTrue( csv[3] == "" );
            assertTrue( csv.size()== 4 );
        }

        csv.setData("abcdef\nghijk\r\nlmnop"); {
            assertTrue( csv[0] == "abcdef" );     assertTrue( csv[0] != "abcdef\n" );
            assertTrue( csv.size()== 1 );
        //  assertTrue( csv[1] != "ghijk\r\n" );  assertTrue( csv[1] == "" );
        //  assertTrue( csv[2] != "lmnop" );      assertTrue( csv[2] == "" );
        }

        csv.setData("abcdef\rghijk\r\nlmnop"); {
            assertTrue( csv[0] != "abcdef\rghijk\r\n" );
            assertTrue( csv[0] == "abcdef\rghijk" );
            assertTrue( csv.size()== 1 );
        //  assertTrue( csv[1] == "" );
        }
    }
    {   // A73869-A74668
        {
            CSV_line csv( "\n"  );
            assertTrue( csv.size() == 1 );
            assertTrue( csv[0] == "" );
        }
        {
            CSV_line csv( ",\".\"\rab,"  ); // [,"."\rab,]
            assertTrue( csv.size() == 3 );
            assertTrue( csv[0] == "" );
            assertTrue( csv[1] == "\".\"\rab" );
            assertTrue( csv[1] != ".\rab" );
            assertTrue( csv[2] == "" );
        }
        {
            CSV_line csv( ",\".\"ab,\"hola\"\n"  );
            assertTrue( csv.size() == 3 );
            assertTrue( csv[0] == "" );
            assertTrue( csv[1] == "\".\"ab" );
        }
    }
}

/// Test ==> CSV_line.operator[]().
void test_CSV::test_op_data() {
    // A73869-A74668
    {{  // test::op_data()
        CSV_line csv ("a,b,c,d,e,f,g"); {
            assertTrue(csv[0] == "a");
            assertTrue(csv[1] == "b");
            assertTrue(csv[2] == "c");
            assertTrue(csv[3] == "d");
            assertTrue(csv[4] == "e");
            assertTrue(csv[5] == "f");
            assertTrue( csv.size() == 7 );
        }
    }}
    {   // A73869-A74668
        CSV_line csv2 ( "poll, m, ts, 08" ); {
            assertTrue(csv2[0] == "poll");
            assertTrue(csv2[1] == " m");
            assertTrue(csv2[2] == " ts");
            assertTrue(csv2[3] == " 08");
            assertTrue(csv2.size() == 4 );
        }

        CSV_line csv3 ("fsd,ah,que,pi,som,b,aaana"); {
            assertTrue(csv3[0] == "fsd");
            assertTrue(csv3[1] == "ah");
            assertTrue(csv3[2] == "que");
            assertTrue(csv3[3] == "pi");
            assertTrue(csv3[4] == "som");
            assertTrue(csv3[5] == "b");
            assertTrue( csv3.size() == 7 );
        }
    }
}

/// Test ==> \c setQuotedCSV().
void test_CSV::test_setQuotedCSV() {
    // A73869-A74668
    {{  // test::setQuotedCSV()
        std::string res;
        setQuotedCSV( res, ","    );  assertTrue( res == "\",\"" );     // [","]
        setQuotedCSV( res, "2"    );  assertTrue( res == "2" );         // [2]
        setQuotedCSV( res, ""     );  assertTrue( res == "" );          // []
        setQuotedCSV( res, "4,5"  );  assertTrue( res == "\"4,5\"" );   // ["4,5"]
        setQuotedCSV( res, "K\""  );  assertTrue( res == "\"K\"\"\"" ); // ["K"""]
        setQuotedCSV( res, "\r\n" );  assertTrue( res == "\"\r\n\"" );  // ["\r\n"]
    }}
    {   // A24444-A71569
        std::string dest, str;
        str = "valor1"; setQuotedCSV(dest, str);
        assertTrue( dest == "valor1" );
        str = "valor 1"; setQuotedCSV(dest, str);
        assertTrue( dest == "\"valor 1\"" );
        str = "valor,1"; setQuotedCSV(dest, str);
        assertTrue( dest == "\"valor,1\"" );
        str = "valor\"1"; setQuotedCSV(dest, str);
        assertTrue( dest == "\"valor\"\"1\"" );
        str = "valor,\"1\""; setQuotedCSV(dest, str);
        assertTrue( dest == "\"valor,\"\"1\"\"\"" );
    }
    {   // A56254
        std::string res;
        setQuotedCSV( res, ""       );  assertTrue( res == "" );
        setQuotedCSV( res, "2"      );  assertTrue( res == "2" );
        setQuotedCSV( res, "4,5"    );  assertTrue( res == "\"4,5\"" );
        setQuotedCSV( res, "& _ ()" );  assertTrue( res == "\"& _ ()\"" );
    }
    {  // A61166
        std::string res, str;
        res = str = "1 2 3 4 5 6"; {
            assertTrue ( res == "1 2 3 4 5 6" );
            setQuotedCSV (res, str);
            assertTrue ( res != str );
            assertTrue ( res == "\"1 2 3 4 5 6\"" );
        }
        res = str = "1,2,3,4,5,6"; {
            assertTrue ( res == "1,2,3,4,5,6" );
            setQuotedCSV (res, str);
            assertTrue ( res != str );
            assertTrue ( res == "\"1,2,3,4,5,6\"" );
        }
        res = str = "123\"456"; {
            assertTrue ( res == "123\"456" );
            setQuotedCSV (res, str);
            assertTrue ( res != str );
            assertTrue ( res == "\"123\"\"456\"" );
        }
        res = str = "123456"; {
            assertTrue ( res == "123456" );
            setQuotedCSV (res, str);
            assertTrue ( res == str );
            assertTrue ( res == "123456" );
        }
        res = str = "\""; {
            assertTrue ( res == "\"" );
            setQuotedCSV (res, str);
            assertTrue ( res != str );
            assertTrue ( res == "\"\"\"\"" );
        }
    }
}

/// Test ==> \c getNextCSV().
void test_CSV::test_getNextCSV() {
    {  // A73869-A74668
        std::string prueba1 = "PSL,ITE,AMCY";
        std::istringstream ist(prueba1);
        bool getn1 = getNextCSV(prueba1,ist);
        assertFalse (getn1);
        assertTrue (prueba1 == "PSL");

        if (false) {
            {
                int error; //para inducir un error en CIN
                std::string res;
                std::cout << "Digite una letra para provocar un error";
                std::cin >> error;
                bool fallo = getNextCSV(res,std::cin);
                assertTrue(!fallo);
            }
            {
                int error1; //para inducir un error en CIN
                std::string res1;
                std::cin >> error1;
                bool fallo1 = getNextCSV(res1,std::cin);
                assertTrue(!fallo1);
            }
            {
                int error2; //para inducir un error en CIN
                std::string res2;
                std::cin >> error2;
                bool fallo2 = getNextCSV(res2,std::cin);
                assertTrue(!fallo2);
            }
            {
                std::string prueba2 = "PSL\n";
                std::istringstream ist2 (prueba2);
                bool getn1 = getNextCSV(prueba2,ist2);
                assertTrue (getn1);
                assertTrue (prueba2 == "PSL");
            }
        }
    }
    {   // A56254
        std::string csv; {
            std::string str1 = "a";
            std::istringstream ist1(str1);
            getNextCSV( csv, ist1 );  assertTrue( csv == "a" );

            std::string str2 = "\"2,3\"";
            std::istringstream ist2(str2);
            getNextCSV( csv, ist2 );  assertTrue( csv == "2,3" );

            std::string str3 = "\n";
            std::istringstream ist3(str3);
            getNextCSV( csv, ist3 );  assertTrue( csv == "" );
        }
    }
}

/// Test ==> \c trim().
void test_CSV::test_trim() {
    {{  // test::trim()
        std::string str;
        str = " a b   "; trim(str); assertTrue( str == "a b"  );
        str = "  a\nb "; trim(str); assertTrue( str == "a\nb" );
        str = "";        trim(str); assertTrue( str == ""     );
        str = "\r\t\n "; trim(str); assertTrue( str == ""     );
        str = " a b ";   trim(str); assertTrue( str == "a b"  );
        str = " ab " ;   trim(str); assertTrue( str == "ab"   );
    }}
}

/// Test ==> \c trimCSV().
void test_CSV::test_trimCSV() {
    {{  // test::trimCSV()
        CSV_line csv("\"zero\",  \"if \"\" 1\" , , \" 3xt\"  \r\f"); std::string s;
        s=csv[0]; assertTrue( s == "zero" );             trimCSV(s); assertTrue( s == "zero"    );
        s=csv[1]; assertTrue( s == "  \"if \"\" 1\" " ); trimCSV(s); assertTrue( s == "if \" 1" );
        s=csv[2]; assertTrue( s == " " );                trimCSV(s); assertTrue( s == ""        );
        s=csv[3]; assertTrue( s == " \" 3xt\"  \r\f" );  trimCSV(s); assertTrue( s == " 3xt"    );
    }}
    {{
        //              ["zero",  "if "" 1" , , " 3xt"  \r\n]
        CSV_line csv ("\"zero\",  \"if \"\" 1\" , , \" 3xt\"  \r\n");
        std::vector<std::string> cpy = csv;
        assertTrue( csv[0] == "zero" );             // [zero]
        assertTrue( csv[1] == "  \"if \"\" 1\" " ); // [  "if "" 1" ]
        assertTrue( csv[2] == " " );                // [ ]
        assertTrue( csv[3] == " \" 3xt\"  " );      // [ " 3xt"  ]

        trimCSV( cpy[0] ); assertTrue( cpy[0] == "zero"    ); // [zero]
        trimCSV( cpy[1] ); assertTrue( cpy[1] == "if \" 1" ); // [if " 1]
        trimCSV( cpy[2] ); assertTrue( cpy[2] == ""        ); // []
        trimCSV( cpy[3] ); assertTrue( cpy[3] == " 3xt"    ); // [ 3xt]
    }}
}

#ifdef C_CSV

#include "CSV.c"

/// Test ==> \c trim() [C].
void test_CSV::test_trim_C() {
    #define googa std::cout << "trim(" << str << ")==> ["; std::cout << trim(str) << ']' << std::endl;
    {{  // test::trim_C()
        char str[20];
        strcpy( str , " a b   " ); assertTrue( strcmp( trim(str), "a b" ) == 0 );
        strcpy( str , "  a\nb " ); assertTrue( strcmp( trim(str), "a\nb") == 0 );
        strcpy( str , ""        ); assertTrue( strcmp( trim(str), ""    ) == 0 );
        strcpy( str , "\r\t\n " ); assertTrue( strcmp( trim(str), ""    ) == 0 );
        strcpy( str , " a b "   ); assertTrue( strcmp( trim(str), "a b" ) == 0 );
        strcpy( str , " ab "    ); assertTrue( strcmp( trim(str), "ab"  ) == 0 );

    }}
}

/// Test ==> \c chop() [C].
void test_CSV::test_chop_C() {
    {{  // test::chop_C()
        char str[20]; char ch;
        strcpy( str , "12345") ; assertTrue( strcmp(str ,"12345")==0 );
        chop(str,'0');           assertTrue( strcmp(str ,"12345")==0 );

        for ( ch='5'; ch != '0'; --ch ) {
            assertTrue( str[strlen(str)-1] == ch );
            chop(str,ch);
        }

        assertTrue( *str == 0 );
        chop(str,'3'); assertTrue( *str == 0 );
    }}
}
#endif

/// Test ==> \c chop().
void test_CSV::test_chop() {
    {{  // test::chop()
        std::string str; char ch;
        str = "12345"; assertTrue( str == "12345" );
        chop(str,'0'); assertTrue( str == "12345" );

        for ( ch='5'; ch != '0'; --ch ) {
            assertTrue( str[str.size()-1] == ch );
            chop(str,ch);
        }

        assertTrue( str == "" );
        chop(str,'3'); assertTrue( str == "" );
    }}
}

#include <sstream> // basic_istringstream<>

#ifdef English_dox
/// Shows the correct way to read \c str usign \c sstream.
/// - A \c basic_istringstream<> is used to read from \c str.
/// - The result gets stored into \c res.
/// - Reading is done using \c operator<<().
#endif
#ifdef Spanish_dox
/// Muestra la forma correcta de leer la hilera \c str usando \c sstream.
/// - Se usa \c basic_istringstream<> para leer desde \c str.
/// - El resultado leído se deposita en \c res.
/// - La lectura se hace usando el operador \c operator<<().
#endif
void mem_istring( std::string & res , std::string & str ) {
    //  typedef basic_istringstream<char> istringstream;
    {
        std::istringstream ist(str); // std::basic_istringstream<char> ist(str);
        getNextCSV( res, ist );
    }
    {
        res.clear();
        std::basic_istringstream<char> ist(str); // std::istringstream ist(str);
        char ch='%'; int i =0;
        while ( ! ist.eof() ) {  // see http://www.horstmann.com/cpp/pitfalls.html
            ist >> ch; ++i;
            res += ch;
            ch = '!';
        }
    //  std::cout << '[' << res << ']' << '(' << i << ')' << std::endl;
    }
    {
        res.clear();
        std::istringstream ist(str); // std::basic_istringstream<char> ist(str);
        char ch='%'; int i =0;
        for (;;) {
            ist.get( ch ); ++i;
            if ( ist.eof() ) {  // see http://www.horstmann.com/cpp/pitfalls.html
                break;
            }
            res += ch;
            ch = '!';
        }
    //  std::cout << '[' << res << ']' << '(' << i << ')' << std::endl;
    }
    {
        res.clear();
        std::istringstream ist(str); // std::basic_istringstream<char> ist(str);
        char ch='%'; int i =0;
        for (;;) {
            ist >> ch; ++i;
            if ( ist.eof() ) {  // see http://www.horstmann.com/cpp/pitfalls.html
                break;
            }
            res += ch;
            ch = '!';
        }
    //  std::cout << '[' << res << ']' << '(' << i << ')' << std::endl;
    }
}

/// Test ==> \c istringstream().
void test_CSV::test_istringstream() {
    {
        std::string res, str = " 1 2 3 4 5 6 ";
        mem_istring( res , str );
        assertTrue( res != "1234566" );
        assertTrue( res != " 1 2 3 4 5 6 " );
        assertTrue( res == "123456" );
    }
}


#ifdef English_dox
/// Main program that executes the tests.
#endif
#ifdef Spanish_dox
/// Programa principal que ejecuta la prueba.
#endif
int main() {
    test_CSV tester;
    tester.run();
    std::cout << tester.report();
    return 0;
}

// EOF: test_CSV
