LCOV - code coverage report
Current view: top level - tests - test_as2js_stream.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 703 759 92.6 %
Date: 2014-11-22 Functions: 19 19 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* test_as2js_stream.cpp -- written by Alexis WILKE for Made to Order Software Corp. (c) 2005-2014 */
       2             : 
       3             : /*
       4             : 
       5             : Copyright (c) 2005-2014 Made to Order Software Corp.
       6             : 
       7             : http://snapwebsites.org/project/as2js
       8             : 
       9             : Permission is hereby granted, free of charge, to any
      10             : person obtaining a copy of this software and
      11             : associated documentation files (the "Software"), to
      12             : deal in the Software without restriction, including
      13             : without limitation the rights to use, copy, modify,
      14             : merge, publish, distribute, sublicense, and/or sell
      15             : copies of the Software, and to permit persons to whom
      16             : the Software is furnished to do so, subject to the
      17             : following conditions:
      18             : 
      19             : The above copyright notice and this permission notice
      20             : shall be included in all copies or substantial
      21             : portions of the Software.
      22             : 
      23             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
      24             : ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
      25             : LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
      26             : FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
      27             : EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      28             : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      29             : WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      30             : ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      31             : SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      32             : SOFTWARE.
      33             : 
      34             : */
      35             : 
      36             : #include    "test_as2js_stream.h"
      37             : #include    "test_as2js_main.h"
      38             : 
      39             : #include    "as2js/stream.h"
      40             : #include    "as2js/exceptions.h"
      41             : 
      42             : #include    <cstring>
      43             : #include    <algorithm>
      44             : #include    <sstream>
      45             : 
      46             : #include    <unistd.h>
      47             : #include    <fcntl.h>
      48             : 
      49             : #include    <cppunit/config/SourcePrefix.h>
      50           4 : CPPUNIT_TEST_SUITE_REGISTRATION( As2JsStreamUnitTests );
      51             : 
      52             : 
      53             : namespace
      54             : {
      55             : 
      56     2097406 : int wctombs(char *mb, uint32_t wc)
      57             : {
      58     2097406 :     if(wc < 0x80)
      59             :     {
      60             :         /* this will also encode '\0'... */
      61         127 :         mb[0] = static_cast<char>(wc);
      62         127 :         mb[1] = '\0';
      63         127 :         return 1;
      64             :     }
      65     2097279 :     if(wc < 0x800)
      66             :     {
      67        1921 :         mb[0] = static_cast<char>((wc >> 6) | 0xC0);
      68        1921 :         mb[1] = (wc & 0x3F) | 0x80;
      69        1921 :         mb[2] = '\0';
      70        1921 :         return 2;
      71             :     }
      72     2095358 :     if(wc < 0x10000)
      73             :     {
      74       63502 :         mb[0] = static_cast<char>((wc >> 12) | 0xE0);
      75       63502 :         mb[1] = ((wc >> 6) & 0x3F) | 0x80;
      76       63502 :         mb[2] = (wc & 0x3F) | 0x80;
      77       63502 :         mb[3] = '\0';
      78       63502 :         return 3;
      79             :     }
      80     2031856 :     if(wc < 0x200000)
      81             :     {
      82     2031856 :         mb[0] = static_cast<char>((wc >> 18) | 0xF0);
      83     2031856 :         mb[1] = ((wc >> 12) & 0x3F) | 0x80;
      84     2031856 :         mb[2] = ((wc >> 6) & 0x3F) | 0x80;
      85     2031856 :         mb[3] = (wc & 0x3F) | 0x80;
      86     2031856 :         mb[4] = '\0';
      87     2031856 :         return 4;
      88             :     }
      89           0 :     if(wc < 0x4000000)
      90             :     {
      91           0 :         mb[0] = (wc >> 24) | 0xF8;
      92           0 :         mb[1] = ((wc >> 18) & 0x3F) | 0x80;
      93           0 :         mb[2] = ((wc >> 12) & 0x3F) | 0x80;
      94           0 :         mb[3] = ((wc >> 6) & 0x3F) | 0x80;
      95           0 :         mb[4] = (wc & 0x3F) | 0x80;
      96           0 :         mb[5] = '\0';
      97           0 :         return 5;
      98             :     }
      99           0 :     if(wc > 0)    // <=> (uint32_t) wc < 0x80000000
     100             :     {
     101           0 :         mb[0] = (wc >> 30) | 0xFC;
     102           0 :         mb[1] = ((wc >> 24) & 0x3F) | 0x80;
     103           0 :         mb[2] = ((wc >> 18) & 0x3F) | 0x80;
     104           0 :         mb[3] = ((wc >> 12) & 0x3F) | 0x80;
     105           0 :         mb[4] = ((wc >> 6) & 0x3F) | 0x80;
     106           0 :         mb[5] = (wc & 0x3F) | 0x80;
     107           0 :         mb[6] = '\0';
     108           0 :         return 6;
     109             :     }
     110             : 
     111             :     /* an invalid wide character (negative!) simply not encoded */
     112           0 :     mb[0] = '\0';
     113           0 :     return 0;
     114             : }
     115             : 
     116             : }
     117             : // no name namespace
     118             : 
     119             : 
     120             : 
     121             : 
     122           1 : void As2JsStreamUnitTests::test_filter_iso88591()
     123             : {
     124             :     {
     125           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterISO88591);
     126         256 :         for(int c(1); c < 256; ++c)
     127             :         {
     128         255 :             filter->putc(c);
     129         255 :             CPPUNIT_ASSERT(filter->getc() == c);
     130             :         }
     131             :         // check EOF and make sure it remains that way
     132         257 :         for(int c(0); c < 256; ++c)
     133             :         {
     134         256 :             CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     135           1 :         }
     136             :     }
     137             :     {
     138           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterISO88591);
     139         256 :         for(int c(1); c < 256; ++c)
     140             :         {
     141         255 :             filter->putc(c);
     142             :         }
     143         256 :         for(int c(1); c < 256; ++c)
     144             :         {
     145         255 :             CPPUNIT_ASSERT(filter->getc() == c);
     146             :         }
     147           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     148             : 
     149             :         // then try with random data
     150             :         int buf[256];
     151         257 :         for(int c(0); c < 256; ++c)
     152             :         {
     153         256 :             CPPUNIT_ASSERT(static_cast<size_t>(c) < sizeof(buf) / sizeof(buf[0]));
     154         258 :             do
     155             :             {
     156         258 :                 buf[c] = rand() & 0xFF;
     157             :             }
     158         258 :             while(buf[c] == 0);
     159         256 :             filter->putc(buf[c]);
     160             :         }
     161         257 :         for(int c(0); c < 256; ++c)
     162             :         {
     163         256 :             CPPUNIT_ASSERT(filter->getc() == buf[c]);
     164             :         }
     165           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     166           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     167           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     168             :     }
     169           1 : }
     170             : 
     171             : 
     172           1 : void As2JsStreamUnitTests::test_filter_utf8()
     173             : {
     174             :     {
     175           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterUTF8);
     176             : 
     177             :         // The Stream reimplements its own UTF-8 conversion so we want to
     178             :         // test all the characters here...
     179     2097151 :         for(as2js::as_char_t wc(1); wc < 0x1FFFFF; ++wc)
     180             :         {
     181     2097150 :             if((wc & 0xFFFF) == 0)
     182             :             {
     183          31 :                 std::cout << "." << std::flush;
     184             :             }
     185             : 
     186     2097150 :             bool err(wc >= 0xD800 && wc <= 0xDFFF || wc > 0x10FFFF);
     187             : 
     188             :             // 1 to 7 character strings
     189             :             char buf[10];
     190     2097150 :             wctombs(buf, wc);
     191             : 
     192    10418041 :             for(size_t idx(0); buf[idx] != '\0'; ++idx)
     193             :             {
     194     8320891 :                 filter->putc(buf[idx]);
     195     8320891 :                 if(buf[idx + 1] == '\0')
     196             :                 {
     197     2097150 :                     if(err)
     198             :                     {
     199             :                         // invalid characters must return an error
     200      985087 :                         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_ERR);
     201             :                     }
     202             :                     else //if(wc != as2js::String::STRING_BOM)
     203             :                     {
     204     1112063 :                         as2js::as_char_t get_wc(filter->getc());
     205             : //std::cerr << "got " << get_wc << ", expected " << wc << "\n";
     206     1112063 :                         CPPUNIT_ASSERT(get_wc == wc);
     207             :                     }
     208     2097150 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     209     2097150 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     210     2097150 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     211             :                 }
     212             :                 else
     213             :                 {
     214             :                     // NAC remains any number of times until we add
     215             :                     // enough bytes to the input
     216     6223741 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     217     6223741 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     218     6223741 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     219             :                 }
     220             :             }
     221             :         }
     222           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     223           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     224           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     225             :     }
     226             : 
     227             :     // now check sending many characters with putc() and reading them back later
     228             :     {
     229           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterUTF8);
     230             : 
     231           2 :         as2js::String result;
     232         257 :         for(int c(0); c < 256; ++c)
     233             :         {
     234             :             // 5 to 9 character strings
     235             :             int32_t wc;
     236         474 :             do
     237             :             {
     238             :                 // generate a random Unicode character
     239         474 :                 wc = ((rand() << 16) ^ rand()) & 0x1FFFFF;
     240             :             }
     241         460 :             while((wc >= 0xD800 && wc <= 0xDFFF) || wc >= 0x110000);
     242             :             char buf[10];
     243         256 :             wctombs(buf, wc);
     244        1264 :             for(int idx(0); buf[idx] != '\0'; ++idx)
     245             :             {
     246        1008 :                 filter->putc(buf[idx]);
     247             :             }
     248             :             //if(wc != as2js::String::STRING_BOM)
     249             :             {
     250         256 :                 result += wc;
     251             :             }
     252             :         }
     253             : 
     254         257 :         for(size_t idx(0); idx < result.length(); ++idx)
     255             :         {
     256         256 :             as2js::as_char_t get_wc(filter->getc());
     257             : //std::cerr << get_wc << " vs. " << result[idx];
     258         256 :             CPPUNIT_ASSERT(get_wc == result[idx]);
     259             :         }
     260           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     261           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     262           2 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     263             :     }
     264             : 
     265             :     // bytes F8 to FF generate errors immedately
     266             :     {
     267           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterUTF8);
     268             : 
     269           9 :         for(int idx(0xF8); idx < 0x100; ++idx)
     270             :         {
     271           8 :             filter->putc(idx);
     272           8 :             CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_ERR);
     273           8 :             CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     274             :         }
     275           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     276           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     277             :     }
     278             : 
     279             :     // invalid continue bytes test
     280             : //std::cerr << "\n";
     281             :     {
     282           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterUTF8);
     283             : 
     284          57 :         for(int idx(0xC0); idx < 0xF8; ++idx)
     285             :         {
     286             : //std::cerr << std::hex << "testing " << idx;
     287          56 :             filter->putc(idx);
     288          56 :             as2js::as_char_t bad, extra1, extra2, extra3(0);
     289          68 :             do
     290             :             {
     291          68 :                 bad = rand() & 0xFF;
     292             :             }
     293          30 :             while(bad >= 0x80 && bad <= 0xBF); // skip valid bytes
     294             : //std::cerr << std::hex << " + " << bad;
     295          56 :             filter->putc(bad);
     296          56 :             if(idx >= 0xE0)
     297             :             {
     298          25 :                 do
     299             :                 {
     300          25 :                     extra1 = rand() & 0x7F;
     301             :                 }
     302             :                 while(extra1 == 0);
     303          24 :                 filter->putc(extra1);
     304             : //std::cerr << std::hex << " + " << extra1;
     305             :             }
     306             :             else
     307             :             {
     308          32 :                 extra1 = 0;
     309             :             }
     310          56 :             if(idx >= 0xF0)
     311             :             {
     312           8 :                 do
     313             :                 {
     314           8 :                     extra2 = rand() & 0x7F;
     315             :                 }
     316             :                 while(extra2 == 0);
     317           8 :                 filter->putc(extra2);
     318             : //std::cerr << std::hex << " + " << extra2;
     319             :             }
     320             :             else
     321             :             {
     322          48 :                 extra2 = 0;
     323             :             }
     324             : //std::cerr << "\n";
     325          56 :             CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_ERR);
     326             :             // the bad byte is still there, check it...
     327          56 :             if(bad < 0x80)
     328             :             {
     329             :                 // load a normal ISO-8859-1 character
     330          38 :                 CPPUNIT_ASSERT(filter->getc() == bad);
     331          38 :                 if(extra1 != 0)
     332             :                 {
     333          17 :                     CPPUNIT_ASSERT(filter->getc() == extra1);
     334             :                 }
     335          38 :                 if(extra2 != 0)
     336             :                 {
     337           6 :                     CPPUNIT_ASSERT(filter->getc() == extra2);
     338             :                 }
     339             :             }
     340          18 :             else if(bad >= 0xC0 && bad < 0xE0)
     341             :             {
     342             :                 // do something to reset the state
     343          10 :                 if(extra1 == 0)
     344             :                 {
     345           3 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     346             : 
     347           3 :                     extra1 = rand() & 0x7F;
     348           3 :                     filter->putc(extra1);
     349           3 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_ERR);
     350           3 :                     CPPUNIT_ASSERT(filter->getc() == extra1);
     351             :                 }
     352             :                 else
     353             :                 {
     354           2 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_ERR);
     355           2 :                     CPPUNIT_ASSERT(filter->getc() == extra1);
     356           2 :                     if(extra2 != 0)
     357             :                     {
     358           1 :                         CPPUNIT_ASSERT(filter->getc() == extra2);
     359             :                     }
     360             :                 }
     361             :             }
     362          13 :             else if(bad >= 0xE0 && bad < 0xF0)
     363             :             {
     364          16 :                 if(extra1 == 0)
     365             :                 {
     366           5 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     367           5 :                     extra1 = rand() & 0x7F;
     368           5 :                     filter->putc(extra1);
     369           5 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     370           5 :                     extra2 = rand() & 0x7F;
     371           5 :                     filter->putc(extra2);
     372           5 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_ERR);
     373           5 :                     CPPUNIT_ASSERT(filter->getc() == extra1);
     374           5 :                     CPPUNIT_ASSERT(filter->getc() == extra2);
     375             :                 }
     376           3 :                 else if(extra2 == 0)
     377             :                 {
     378           2 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     379           2 :                     extra2 = rand() & 0x7F;
     380           2 :                     filter->putc(extra2);
     381           2 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_ERR);
     382           2 :                     CPPUNIT_ASSERT(filter->getc() == extra1);
     383           2 :                     CPPUNIT_ASSERT(filter->getc() == extra2);
     384             :                 }
     385             :                 else
     386             :                 {
     387           1 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_ERR);
     388           1 :                     CPPUNIT_ASSERT(filter->getc() == extra1);
     389           1 :                     CPPUNIT_ASSERT(filter->getc() == extra2);
     390             :                 }
     391             :             }
     392           5 :             else if(bad >= 0xF0 && bad < 0xF8)
     393             :             {
     394           2 :                 if(extra1 == 0)
     395             :                 {
     396           1 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     397           1 :                     extra1 = rand() & 0x7F;
     398           1 :                     filter->putc(extra1);
     399           1 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     400           1 :                     extra2 = rand() & 0x7F;
     401           1 :                     filter->putc(extra2);
     402           1 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     403           1 :                     extra3 = rand() & 0x7F;
     404           1 :                     filter->putc(extra3);
     405           1 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_ERR);
     406           1 :                     CPPUNIT_ASSERT(filter->getc() == extra1);
     407           1 :                     CPPUNIT_ASSERT(filter->getc() == extra2);
     408           1 :                     CPPUNIT_ASSERT(filter->getc() == extra3);
     409             :                 }
     410           0 :                 else if(extra2 == 0)
     411             :                 {
     412           0 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     413           0 :                     extra2 = rand() & 0x7F;
     414           0 :                     filter->putc(extra2);
     415           0 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     416           0 :                     extra3 = rand() & 0x7F;
     417           0 :                     filter->putc(extra3);
     418           0 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_ERR);
     419           0 :                     CPPUNIT_ASSERT(filter->getc() == extra1);
     420           0 :                     CPPUNIT_ASSERT(filter->getc() == extra2);
     421           0 :                     CPPUNIT_ASSERT(filter->getc() == extra3);
     422             :                 }
     423             :                 else
     424             :                 {
     425           0 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     426           0 :                     extra3 = rand() & 0x7F;
     427           0 :                     filter->putc(extra3);
     428           0 :                     CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_ERR);
     429           0 :                     CPPUNIT_ASSERT(filter->getc() == extra1);
     430           0 :                     CPPUNIT_ASSERT(filter->getc() == extra2);
     431           0 :                     CPPUNIT_ASSERT(filter->getc() == extra3);
     432             :                 }
     433             :             }
     434             :             else
     435             :             {
     436           4 :                 CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_ERR);
     437           4 :                 if(extra1 != 0)
     438             :                 {
     439           2 :                     CPPUNIT_ASSERT(filter->getc() == extra1);
     440             :                 }
     441           4 :                 if(extra2 != 0)
     442             :                 {
     443           0 :                     CPPUNIT_ASSERT(filter->getc() == extra2);
     444             :                 }
     445             :             }
     446             :             // make sure the buffer is empty
     447          56 :             CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     448             :         }
     449           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     450           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     451             :     }
     452           1 : }
     453             : 
     454             : 
     455           1 : void As2JsStreamUnitTests::test_filter_utf16()
     456             : {
     457             :     {
     458           1 :         as2js::DecodingFilter *filter_be(new as2js::DecodingFilterUTF16BE);
     459           1 :         as2js::DecodingFilter *filter_le(new as2js::DecodingFilterUTF16LE);
     460             : 
     461             :         // The Stream reimplements its own UTF-16 conversion so we want to
     462             :         // test all the characters here... Also we have a BE and an LE
     463             :         // version so we check both at the same time; just valid characters
     464     1114112 :         for(as2js::as_char_t wc(1); wc < 0x110000; ++wc)
     465             :         {
     466     1114111 :             if((wc & 0xFFFF) == 0)
     467             :             {
     468          16 :                 std::cout << "." << std::flush;
     469             :             }
     470             : 
     471     1114111 :             if(wc >= 0xD800 && wc <= 0xDFFF)
     472             :             {
     473        2048 :                 continue;
     474             :             }
     475             : 
     476             :             // putc() accepts bytes only, so we need to break down all those
     477             :             // character into bytes as expected by the respective filter
     478     1112063 :             if(wc > 0xFFFF)
     479             :             {
     480             :                 // in this case we need to send 2x uint16_t values
     481     1048576 :                 uint16_t lead((((wc - 0x10000) >> 10) & 0x03FF) | 0xD800);
     482     1048576 :                 uint16_t trail(((wc - 0x10000) & 0x03FF) | 0xDC00);
     483             : 
     484     1048576 :                 filter_be->putc(lead >> 8);
     485     1048576 :                 filter_be->putc(lead & 255);
     486     1048576 :                 filter_be->putc(trail >> 8);
     487     1048576 :                 filter_be->putc(trail & 255);
     488     1048576 :                 CPPUNIT_ASSERT(filter_be->getc() == wc);
     489             : 
     490             :                 // little endian swaps bytes, not the lead & trail
     491     1048576 :                 filter_le->putc(lead & 255);
     492     1048576 :                 filter_le->putc(lead >> 8);
     493     1048576 :                 filter_le->putc(trail & 255);
     494     1048576 :                 filter_le->putc(trail >> 8);
     495     1048576 :                 CPPUNIT_ASSERT(filter_le->getc() == wc);
     496             :             }
     497             :             //else if(wc == as2js::String::STRING_BOM)
     498             :             //{
     499             :             //    // the BOM is never returned
     500             :             //    filter_be->putc(wc >> 8);
     501             :             //    filter_be->putc(wc & 255);
     502             :             //    CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     503             : 
     504             :             //    filter_le->putc(wc & 255);
     505             :             //    filter_le->putc(wc >> 8);
     506             :             //    CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     507             :             //}
     508             :             else
     509             :             {
     510       63487 :                 filter_be->putc(wc >> 8);
     511       63487 :                 filter_be->putc(wc & 255);
     512       63487 :                 as2js::as_char_t get_wc(filter_be->getc());
     513             : //std::cerr << "wc " << wc << " got " << get_wc << "\n";
     514       63487 :                 CPPUNIT_ASSERT(get_wc == wc);
     515             : 
     516       63487 :                 filter_le->putc(wc & 255);
     517       63487 :                 filter_le->putc(wc >> 8);
     518       63487 :                 CPPUNIT_ASSERT(filter_le->getc() == wc);
     519             :             }
     520             :         }
     521           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     522           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     523           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     524           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     525           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     526           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     527             :     }
     528             : 
     529             :     // do it again, this time try all the NAC
     530             :     {
     531           1 :         as2js::DecodingFilter *filter_be(new as2js::DecodingFilterUTF16BE);
     532           1 :         as2js::DecodingFilter *filter_le(new as2js::DecodingFilterUTF16LE);
     533             : 
     534             :         // The Stream reimplements its own UTF-16 conversion so we want to
     535             :         // test all the characters here... Also we have a BE and an LE
     536             :         // version so we check both at the same time; just valid characters
     537     1114112 :         for(as2js::as_char_t wc(1); wc < 0x110000; ++wc)
     538             :         {
     539     1114111 :             if((wc & 0xFFFF) == 0)
     540             :             {
     541          16 :                 std::cout << "." << std::flush;
     542             :             }
     543             : 
     544     1114111 :             if(wc >= 0xD800 && wc <= 0xDFFF)
     545             :             {
     546        2048 :                 continue;
     547             :             }
     548             : 
     549             :             // putc() accepts bytes only, so we need to break down all those
     550             :             // character into bytes as expected by the respective filter
     551     1112063 :             if(wc > 0xFFFF)
     552             :             {
     553             :                 // in this case we need to send 2x uint16_t values
     554     1048576 :                 uint16_t lead((((wc - 0x10000) >> 10) & 0x03FF) | 0xD800);
     555     1048576 :                 uint16_t trail(((wc - 0x10000) & 0x03FF) | 0xDC00);
     556             : 
     557     1048576 :                 filter_be->putc(lead >> 8);
     558     1048576 :                 CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_NAC);
     559     1048576 :                 filter_be->putc(lead & 255);
     560     1048576 :                 CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_NAC);
     561     1048576 :                 filter_be->putc(trail >> 8);
     562     1048576 :                 CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_NAC);
     563     1048576 :                 filter_be->putc(trail & 255);
     564     1048576 :                 CPPUNIT_ASSERT(filter_be->getc() == wc);
     565             : 
     566             :                 // little endian swaps bytes, not the lead & trail
     567     1048576 :                 filter_le->putc(lead & 255);
     568     1048576 :                 CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_NAC);
     569     1048576 :                 filter_le->putc(lead >> 8);
     570     1048576 :                 CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_NAC);
     571     1048576 :                 filter_le->putc(trail & 255);
     572     1048576 :                 CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_NAC);
     573     1048576 :                 filter_le->putc(trail >> 8);
     574     1048576 :                 CPPUNIT_ASSERT(filter_le->getc() == wc);
     575             :             }
     576             :             //else if(wc == as2js::String::STRING_BOM)
     577             :             //{
     578             :             //    // the BOM is never returned
     579             :             //    filter_be->putc(wc >> 8);
     580             :             //    CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_NAC);
     581             :             //    filter_be->putc(wc & 255);
     582             :             //    CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     583             : 
     584             :             //    filter_le->putc(wc & 255);
     585             :             //    CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_NAC);
     586             :             //    filter_le->putc(wc >> 8);
     587             :             //    CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     588             :             //}
     589             :             else
     590             :             {
     591       63487 :                 filter_be->putc(wc >> 8);
     592       63487 :                 CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_NAC);
     593       63487 :                 filter_be->putc(wc & 255);
     594       63487 :                 as2js::as_char_t get_wc(filter_be->getc());
     595             : //std::cerr << "wc " << wc << " got " << get_wc << "\n";
     596       63487 :                 CPPUNIT_ASSERT(get_wc == wc);
     597             : 
     598       63487 :                 filter_le->putc(wc & 255);
     599       63487 :                 CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_NAC);
     600       63487 :                 filter_le->putc(wc >> 8);
     601       63487 :                 CPPUNIT_ASSERT(filter_le->getc() == wc);
     602             :             }
     603             :         }
     604           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     605           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     606           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     607           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     608           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     609           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     610             :     }
     611             : 
     612             :     // invalid surrogates
     613             :     // (1) trail surrogate without a lead
     614           1 :     std::cout << "." << std::flush;
     615             :     {
     616           1 :         as2js::DecodingFilter *filter_be(new as2js::DecodingFilterUTF16BE);
     617           1 :         as2js::DecodingFilter *filter_le(new as2js::DecodingFilterUTF16LE);
     618             : 
     619             :         // The Stream reimplements its own UTF-16 conversion so we want to
     620             :         // test all the characters here... Also we have a BE and an LE
     621             :         // version so we check both at the same time; just valid characters
     622        1025 :         for(as2js::as_char_t wc(0xDC00); wc < 0xE000; ++wc)
     623             :         {
     624        1024 :             filter_be->putc(wc >> 8);
     625        1024 :             CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_NAC);
     626        1024 :             filter_be->putc(wc & 255);
     627        1024 :             CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_ERR);
     628             : 
     629        1024 :             filter_le->putc(wc & 255);
     630        1024 :             CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_NAC);
     631        1024 :             filter_le->putc(wc >> 8);
     632        1024 :             CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_ERR);
     633             :         }
     634           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     635           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     636           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     637           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     638           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     639           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     640             :     }
     641             : 
     642             :     // invalid surrogates
     643             :     // (2) lead surrogate without a trail
     644           1 :     std::cout << "." << std::flush;
     645             :     {
     646           1 :         as2js::DecodingFilter *filter_be(new as2js::DecodingFilterUTF16BE);
     647           1 :         as2js::DecodingFilter *filter_le(new as2js::DecodingFilterUTF16LE);
     648             : 
     649             :         // The Stream reimplements its own UTF-16 conversion so we want to
     650             :         // test all the characters here... Also we have a BE and an LE
     651             :         // version so we check both at the same time; just valid characters
     652        1025 :         for(as2js::as_char_t wc(0xD800); wc < 0xDC00; ++wc)
     653             :         {
     654             :             // get another character which is not a surrogate
     655             :             as2js::as_char_t extra1;
     656        1060 :             do
     657             :             {
     658        1060 :                 extra1 = rand() & 0x0FFFF;
     659             :             }
     660         164 :             while(extra1 >= 0xD800 && extra1 <= 0xDFFF);
     661             : 
     662        1024 :             filter_be->putc(wc >> 8);
     663        1024 :             CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_NAC);
     664        1024 :             filter_be->putc(wc & 255);
     665        1024 :             CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_NAC);
     666        1024 :             filter_be->putc(extra1 >> 8);
     667        1024 :             CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_NAC);
     668        1024 :             filter_be->putc(extra1 & 255);
     669        1024 :             CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_ERR);
     670        1024 :             as2js::as_char_t get_wc(filter_be->getc());
     671             : //std::cerr << "got " << get_wc << ", expected " << extra1 << "\n";
     672             :             //if(extra1 == as2js::String::STRING_BOM)
     673             :             //{
     674             :             //    CPPUNIT_ASSERT(get_wc == as2js::Input::INPUT_EOF);
     675             :             //}
     676             :             //else
     677             :             {
     678        1024 :                 CPPUNIT_ASSERT(get_wc == extra1);
     679             :             }
     680             : 
     681        1024 :             filter_le->putc(wc & 255);
     682        1024 :             CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_NAC);
     683        1024 :             filter_le->putc(wc >> 8);
     684        1024 :             CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_NAC);
     685        1024 :             filter_le->putc(extra1 & 255);
     686        1024 :             CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_NAC);
     687        1024 :             filter_le->putc(extra1 >> 8);
     688        1024 :             CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_ERR);
     689             :             //if(extra1 == as2js::String::STRING_BOM)
     690             :             //{
     691             :             //    CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     692             :             //}
     693             :             //else
     694             :             {
     695        1024 :                 CPPUNIT_ASSERT(filter_le->getc() == extra1);
     696             :             }
     697             :         }
     698           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     699           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     700           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     701           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     702           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     703           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     704             :     }
     705             : 
     706           1 : }
     707             : 
     708             : 
     709           1 : void As2JsStreamUnitTests::test_filter_utf32()
     710             : {
     711             :     {
     712           1 :         as2js::DecodingFilter *filter_be(new as2js::DecodingFilterUTF32BE);
     713           1 :         as2js::DecodingFilter *filter_le(new as2js::DecodingFilterUTF32LE);
     714             : 
     715             :         // The Stream reimplements its own UTF-16 conversion so we want to
     716             :         // test all the characters here... Also we have a BE and an LE
     717             :         // version so we check both at the same time; just valid characters
     718     2097151 :         for(as2js::as_char_t wc(1); wc < 0x1FFFFF; ++wc)
     719             :         {
     720     2097150 :             if((wc & 0xFFFF) == 0)
     721             :             {
     722          31 :                 std::cout << "." << std::flush;
     723             :             }
     724             : 
     725     2097150 :             bool const err((wc >= 0xD800 && wc <= 0xDFFF) || wc > 0x10FFFF);
     726             : 
     727             :             // putc() accepts bytes only, so we need to break down all those
     728             :             // character into bytes as expected by the respective filter
     729             : 
     730             :             // in this case we need to send 2x uint16_t values
     731             : 
     732     2097150 :             filter_be->putc((wc >> 24) & 255);
     733     2097150 :             CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_NAC);
     734     2097150 :             filter_be->putc((wc >> 16) & 255);
     735     2097150 :             CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_NAC);
     736     2097150 :             filter_be->putc((wc >>  8) & 255);
     737     2097150 :             CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_NAC);
     738     2097150 :             filter_be->putc((wc >>  0) & 255);
     739             :             //if(wc == as2js::String::STRING_BOM)
     740             :             //{
     741             :             //    CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     742             :             //}
     743             :             //else
     744             :             {
     745     2097150 :                 CPPUNIT_ASSERT(filter_be->getc() == (err ? as2js::Input::INPUT_ERR : wc));
     746             :             }
     747             : 
     748             :             // little endian swaps bytes, not the lead & trail
     749     2097150 :             filter_le->putc((wc >>  0) & 255);
     750     2097150 :             CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_NAC);
     751     2097150 :             filter_le->putc((wc >>  8) & 255);
     752     2097150 :             CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_NAC);
     753     2097150 :             filter_le->putc((wc >> 16) & 255);
     754     2097150 :             CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_NAC);
     755     2097150 :             filter_le->putc((wc >> 24) & 255);
     756             :             //if(wc == as2js::String::STRING_BOM)
     757             :             //{
     758             :             //    CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     759             :             //}
     760             :             //else
     761             :             {
     762     2097150 :                 CPPUNIT_ASSERT(filter_le->getc() == (err ? as2js::Input::INPUT_ERR : wc));
     763             :             }
     764             :         }
     765           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     766           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     767           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     768           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     769           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     770           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     771             :     }
     772             : 
     773             :     {
     774           1 :         as2js::DecodingFilter *filter_be(new as2js::DecodingFilterUTF32BE);
     775           1 :         as2js::DecodingFilter *filter_le(new as2js::DecodingFilterUTF32LE);
     776             : 
     777             :         // The Stream reimplements its own UTF-16 conversion so we want to
     778             :         // test all the characters here... Also we have a BE and an LE
     779             :         // version so we check both at the same time; just valid characters
     780           1 :         std::cout << "-" << std::flush;
     781           1 :         std::vector<as2js::as_char_t> result;
     782         257 :         for(as2js::as_char_t idx(0); idx < 256; ++idx)
     783             :         {
     784         256 :             as2js::as_char_t wc(((rand() << 16) ^ rand()) & 0x1FFFFF);
     785             : 
     786             :             //if(wc != as2js::String::STRING_BOM)
     787             :             {
     788         256 :                 result.push_back(wc);
     789             :             }
     790             : 
     791             :             // putc() accepts bytes only, so we need to break down all those
     792             :             // character into bytes as expected by the respective filter
     793             : 
     794             :             // in this case we need to send 2x uint16_t values
     795             : 
     796         256 :             filter_be->putc((wc >> 24) & 255);
     797         256 :             filter_be->putc((wc >> 16) & 255);
     798         256 :             filter_be->putc((wc >>  8) & 255);
     799         256 :             filter_be->putc((wc >>  0) & 255);
     800             : 
     801         256 :             filter_le->putc((wc >>  0) & 255);
     802         256 :             filter_le->putc((wc >>  8) & 255);
     803         256 :             filter_le->putc((wc >> 16) & 255);
     804         256 :             filter_le->putc((wc >> 24) & 255);
     805             :         }
     806           1 :         std::cout << "+" << std::flush;
     807         257 :         for(size_t idx(0); idx < result.size(); ++idx)
     808             :         {
     809         256 :             as2js::as_char_t wc(result[idx]);
     810             : 
     811         256 :             bool const err((wc >= 0xD800 && wc <= 0xDFFF) || wc > 0x10FFFF);
     812             : 
     813         256 :             CPPUNIT_ASSERT(filter_be->getc() == (err ? as2js::Input::INPUT_ERR : wc));
     814         256 :             CPPUNIT_ASSERT(filter_le->getc() == (err ? as2js::Input::INPUT_ERR : wc));
     815             :         }
     816           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     817           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     818           1 :         CPPUNIT_ASSERT(filter_be->getc() == as2js::Input::INPUT_EOF);
     819           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     820           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     821           1 :         CPPUNIT_ASSERT(filter_le->getc() == as2js::Input::INPUT_EOF);
     822             :     }
     823           1 : }
     824             : 
     825             : 
     826           1 : void As2JsStreamUnitTests::test_filter_detect()
     827             : {
     828             :     // test UTF32BE
     829             :     {
     830           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
     831             : 
     832             :         // BOM + 0x10203
     833           1 :         filter->putc(0);
     834           1 :         filter->putc(0);
     835           1 :         filter->putc(0xFE);
     836           1 :         filter->putc(0xFF);
     837           1 :         filter->putc(0);
     838           1 :         filter->putc(1);
     839           1 :         filter->putc(2);
     840           1 :         filter->putc(3);
     841             : 
     842           1 :         as2js::as_char_t wc(filter->getc());
     843           1 :         CPPUNIT_ASSERT(wc == 0x10203);
     844           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     845             :     }
     846             : 
     847             :     // test UTF32LE
     848             :     {
     849           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
     850             : 
     851             :         // BOM + 0x10203
     852           1 :         filter->putc(0xFF);
     853           1 :         filter->putc(0xFE);
     854           1 :         filter->putc(0);
     855           1 :         filter->putc(0);
     856           1 :         filter->putc(3);
     857           1 :         filter->putc(2);
     858           1 :         filter->putc(1);
     859           1 :         filter->putc(0);
     860             : 
     861           1 :         as2js::as_char_t wc(filter->getc());
     862           1 :         CPPUNIT_ASSERT(wc == 0x10203);
     863           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     864             :     }
     865             : 
     866             :     // test UTF16BE
     867             :     {
     868           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
     869             : 
     870             :         // BOM + 0x102
     871           1 :         filter->putc(0xFE);
     872           1 :         filter->putc(0xFF);
     873           1 :         filter->putc(1);
     874           1 :         filter->putc(2);
     875             : 
     876           1 :         as2js::as_char_t wc(filter->getc());
     877           1 :         CPPUNIT_ASSERT(wc == 0x102);
     878           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     879             :     }
     880             : 
     881             :     // test UTF16LE
     882             :     {
     883           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
     884             : 
     885             :         // BOM + 0x102
     886           1 :         filter->putc(0xFF);
     887           1 :         filter->putc(0xFE);
     888           1 :         filter->putc(2);
     889           1 :         filter->putc(1);
     890             : 
     891           1 :         as2js::as_char_t wc(filter->getc());
     892           1 :         CPPUNIT_ASSERT(wc == 0x102);
     893           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     894             :     }
     895             : 
     896             :     // test UTF8 with BOM
     897             :     {
     898           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
     899             : 
     900             :         // BOM + 0x10203
     901           2 :         as2js::String wstr;
     902           1 :         wstr += 0x0000FEFF;     // BOM
     903           1 :         wstr += 0x00010203;     // 0x10203
     904           2 :         std::string utf8(wstr.to_utf8());
     905           8 :         for(size_t idx(0); idx < utf8.size(); ++idx)
     906             :         {
     907           7 :             filter->putc(utf8[idx]);
     908             :         }
     909             : 
     910           1 :         as2js::as_char_t wc(filter->getc());
     911           1 :         CPPUNIT_ASSERT(wc == 0x10203);
     912           2 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     913             :     }
     914             : 
     915             :     // test UTF8 without BOM
     916             :     {
     917           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
     918             : 
     919             :         // 0x10203 and 0x30201
     920           2 :         as2js::String wstr;
     921           1 :         wstr += 0x00010203;
     922           1 :         wstr += 0x00030201;
     923           2 :         std::string utf8(wstr.to_utf8());
     924           9 :         for(size_t idx(0); idx < utf8.size(); ++idx)
     925             :         {
     926           8 :             filter->putc(utf8[idx]);
     927             :         }
     928             : 
     929           1 :         as2js::as_char_t wc(filter->getc());
     930           1 :         CPPUNIT_ASSERT(wc == 0x10203);
     931           1 :         wc = filter->getc();
     932           1 :         CPPUNIT_ASSERT(wc == 0x30201);
     933           2 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     934             :     }
     935             : 
     936             :     // test ISO-8859-1 (fallback)
     937             :     {
     938           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
     939             : 
     940             :         // invalid UTF-8 on the first 4 bytes
     941           1 :         filter->putc(0xFF);
     942           1 :         filter->putc(0x01);
     943           1 :         filter->putc(0x02);
     944           1 :         filter->putc(0x03);
     945             : 
     946           1 :         CPPUNIT_ASSERT(filter->getc() == 0xFF);
     947           1 :         CPPUNIT_ASSERT(filter->getc() == 0x01);
     948           1 :         CPPUNIT_ASSERT(filter->getc() == 0x02);
     949           1 :         CPPUNIT_ASSERT(filter->getc() == 0x03);
     950           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     951             :     }
     952             : 
     953             :     // test UTF32BE with NAC tests
     954             :     {
     955           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
     956             : 
     957             :         // BOM + 0x10203
     958           1 :         filter->putc(0);
     959           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     960           1 :         filter->putc(0);
     961           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     962           1 :         filter->putc(0xFE);
     963           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     964           1 :         filter->putc(0xFF);
     965           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     966           1 :         filter->putc(0);
     967           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     968           1 :         filter->putc(1);
     969           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     970           1 :         filter->putc(2);
     971           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     972           1 :         filter->putc(3);
     973           1 :         CPPUNIT_ASSERT(filter->getc() == 0x10203);
     974           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     975             :     }
     976             : 
     977             :     // test UTF32LE
     978             :     {
     979           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
     980             : 
     981             :         // BOM + 0x10203
     982           1 :         filter->putc(0xFF);
     983           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     984           1 :         filter->putc(0xFE);
     985           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     986           1 :         filter->putc(0);
     987           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     988           1 :         filter->putc(0);
     989           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     990           1 :         filter->putc(3);
     991           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     992           1 :         filter->putc(2);
     993           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     994           1 :         filter->putc(1);
     995           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
     996           1 :         filter->putc(0);
     997           1 :         CPPUNIT_ASSERT(filter->getc() == 0x10203);
     998           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
     999             :     }
    1000             : 
    1001             :     // test UTF16BE
    1002             :     {
    1003           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
    1004             : 
    1005             :         // BOM + 0x102
    1006           1 :         filter->putc(0xFE);
    1007           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
    1008           1 :         filter->putc(0xFF);
    1009           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
    1010           1 :         filter->putc(1);
    1011           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
    1012           1 :         filter->putc(2);
    1013           1 :         CPPUNIT_ASSERT(filter->getc() == 0x102);
    1014           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
    1015             :     }
    1016             : 
    1017             :     // test UTF16LE
    1018             :     {
    1019           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
    1020             : 
    1021             :         // BOM + 0x102
    1022           1 :         filter->putc(0xFF);
    1023           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
    1024           1 :         filter->putc(0xFE);
    1025           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
    1026           1 :         filter->putc(2);
    1027           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
    1028           1 :         filter->putc(1);
    1029           1 :         CPPUNIT_ASSERT(filter->getc() == 0x102);
    1030           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
    1031             :     }
    1032             : 
    1033             :     // test UTF8 with BOM
    1034             :     {
    1035           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
    1036             : 
    1037             :         // BOM + 0x10203
    1038           2 :         as2js::String wstr;
    1039           1 :         wstr += 0x0000FEFF;     // BOM
    1040           1 :         wstr += 0x00010203;     // 0x10203
    1041           2 :         std::string utf8(wstr.to_utf8());
    1042           8 :         for(size_t idx(0); idx < utf8.size(); ++idx)
    1043             :         {
    1044           7 :             filter->putc(utf8[idx]);
    1045           7 :             switch(idx)
    1046             :             {
    1047             :             case 0:
    1048             :             case 1:
    1049             :             case 2:
    1050             :             case 3: // at 3 bytes the BOM is available but not detected yet...
    1051             :             case 4: // at 4 bytes we got the BOM + 1 byte of the next character so we get a NAC again...
    1052             :             case 5:
    1053           6 :                 CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
    1054           6 :                 break;
    1055             : 
    1056             :             case 6:
    1057           1 :                 CPPUNIT_ASSERT(filter->getc() == 0x10203);
    1058           1 :                 break;
    1059             : 
    1060             :             default:
    1061           0 :                 CPPUNIT_ASSERT(false);
    1062           0 :                 break;
    1063             : 
    1064             :             }
    1065             :         }
    1066           2 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_EOF);
    1067             :     }
    1068             : 
    1069             :     // test UTF8 without BOM
    1070             :     {
    1071           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
    1072             : 
    1073             :         // 0x10203 and 0x30201
    1074           2 :         as2js::String wstr;
    1075           1 :         wstr += 0x00010203;
    1076           1 :         wstr += 0x00030201;
    1077           2 :         std::string utf8(wstr.to_utf8());
    1078           9 :         for(size_t idx(0); idx < utf8.size(); ++idx)
    1079             :         {
    1080           8 :             filter->putc(utf8[idx]);
    1081           8 :             switch(idx)
    1082             :             {
    1083             :             case 0:
    1084             :             case 1:
    1085             :             case 2:
    1086             :             case 4:
    1087             :             case 5:
    1088             :             case 6:
    1089           6 :                 CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
    1090           6 :                 break;
    1091             : 
    1092             :             case 3:
    1093           1 :                 CPPUNIT_ASSERT(filter->getc() == 0x10203);
    1094           1 :                 break;
    1095             : 
    1096             :             case 7:
    1097           1 :                 CPPUNIT_ASSERT(filter->getc() == 0x30201);
    1098           1 :                 break;
    1099             : 
    1100             :             default:
    1101           0 :                 CPPUNIT_ASSERT(false);
    1102           0 :                 break;
    1103             : 
    1104             :             }
    1105           1 :         }
    1106             :     }
    1107             : 
    1108             :     // test ISO-8859-1 (fallback)
    1109             :     {
    1110           1 :         as2js::DecodingFilter::pointer_t filter(new as2js::DecodingFilterDetect);
    1111             : 
    1112             :         // invalid UTF-8 on the first 4 bytes
    1113           1 :         filter->putc(0xFF);
    1114           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
    1115           1 :         filter->putc(0x01);
    1116           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
    1117           1 :         filter->putc(0x02);
    1118           1 :         CPPUNIT_ASSERT(filter->getc() == as2js::Input::INPUT_NAC);
    1119           1 :         filter->putc(0x03);
    1120             : 
    1121           1 :         CPPUNIT_ASSERT(filter->getc() == 0xFF);
    1122           1 :         CPPUNIT_ASSERT(filter->getc() == 0x01);
    1123           1 :         CPPUNIT_ASSERT(filter->getc() == 0x02);
    1124           1 :         CPPUNIT_ASSERT(filter->getc() == 0x03);
    1125             :     }
    1126           1 : }
    1127             : 
    1128             : 
    1129           1 : void As2JsStreamUnitTests::test_string_input()
    1130             : {
    1131             :     {
    1132           1 :         as2js::String input_data("This is\nthe\ninput data\n");
    1133           2 :         as2js::Input::pointer_t str_input(new as2js::StringInput(input_data));
    1134             : 
    1135           1 :         CPPUNIT_ASSERT(str_input->get_position().get_line() == 1);
    1136          24 :         for(size_t idx(0); idx < input_data.length(); ++idx)
    1137             :         {
    1138          23 :             as2js::Input::char_t c(str_input->getc());
    1139          23 :             CPPUNIT_ASSERT(c == input_data[idx]);
    1140             :             // the input does not know anything about the position
    1141             :             // so it does not change a bit
    1142          23 :             CPPUNIT_ASSERT(str_input->get_position().get_line() == 1);
    1143           1 :         }
    1144             :     }
    1145             : 
    1146             :     {
    1147           1 :         as2js::String input_data("Here we have another string\n");
    1148           2 :         as2js::Input::pointer_t str_input(new as2js::StringInput(input_data));
    1149             : 
    1150           1 :         CPPUNIT_ASSERT(str_input->get_position().get_line() == 1);
    1151          29 :         for(size_t idx(0); idx < input_data.length(); ++idx)
    1152             :         {
    1153          28 :             as2js::Input::char_t c(str_input->getc());
    1154          28 :             CPPUNIT_ASSERT(c == input_data[idx]);
    1155             : 
    1156             :             // unget and re-get
    1157          28 :             str_input->ungetc(c);
    1158             :             as2js::Input::char_t bad;
    1159          28 :             do
    1160             :             {
    1161          28 :                 bad = (rand() << 16) ^ rand();
    1162             :             }
    1163          17 :             while(bad > 0 && bad < 0x110000);
    1164          28 :             str_input->ungetc(bad); // this will be ignored
    1165          28 :             str_input->ungetc(0); // and this too (0 is rather unlikely otherwise
    1166          28 :             CPPUNIT_ASSERT(str_input->getc() == input_data[idx]);
    1167             : 
    1168             :             // the input does not know anything about the position
    1169             :             // so it does not change a bit
    1170          28 :             CPPUNIT_ASSERT(static_cast<as2js::Input const *>(str_input.get())->get_position().get_line() == 1);
    1171           1 :         }
    1172             :     }
    1173             : 
    1174             :     {
    1175           1 :         as2js::String input_data("This is\nthe\ninput data\n");
    1176           2 :         as2js::Input::pointer_t str_input(new as2js::StringInput(input_data));
    1177             : 
    1178           1 :         CPPUNIT_ASSERT(str_input->get_position().get_line() == 1);
    1179           1 :         int line(1);
    1180          24 :         for(size_t idx(0); idx < input_data.length(); ++idx)
    1181             :         {
    1182          23 :             as2js::Input::char_t c(str_input->getc());
    1183          23 :             CPPUNIT_ASSERT(c == input_data[idx]);
    1184          23 :             if(c == '\n')
    1185             :             {
    1186           3 :                 ++line;
    1187           3 :                 str_input->get_position().new_line();
    1188             :             }
    1189             :             // we handle the '\n' so the line no. increases in this one
    1190          23 :             CPPUNIT_ASSERT(static_cast<as2js::Input const *>(str_input.get())->get_position().get_line() == line);
    1191           1 :         }
    1192             :     }
    1193           1 : }
    1194             : 
    1195             : 
    1196           1 : void As2JsStreamUnitTests::test_stdin()
    1197             : {
    1198             :     {
    1199             :         // 1. create a file with some test in it
    1200             :         char filename[256];
    1201           1 :         strncpy(filename, "/tmp/testXXXXXX.js", sizeof(filename));
    1202           1 :         int fd(mkstemps(filename, 3));
    1203           1 :         char const *input_data("This is\nthe\ninput data\nfor std::cin\n");
    1204           1 :         size_t const len(strlen(input_data));
    1205           1 :         if(write(fd, input_data, len) != static_cast<ssize_t>(len))
    1206             :         {
    1207           0 :             CPPUNIT_ASSERT(!"write failed");
    1208           0 :             return;
    1209             :         }
    1210           1 :         close(fd);
    1211             : 
    1212             :         // 2. put that in std::cin
    1213           1 :         if(freopen(filename, "r", stdin) == nullptr)
    1214             :         {
    1215           0 :             std::cerr << "error: failed to set stdin to a file" << std::endl;
    1216           0 :             CPPUNIT_ASSERT(!"freopen(..., stdin) failed");
    1217           0 :             return;
    1218             :         }
    1219             : 
    1220           1 :         as2js::Input::pointer_t str_input(new as2js::StandardInput);
    1221             : 
    1222             :         // The filename for the StandardInput is set to "-" by default
    1223           1 :         CPPUNIT_ASSERT(str_input->get_position().get_filename() == "-");
    1224             : 
    1225           1 :         CPPUNIT_ASSERT(str_input->get_position().get_line() == 1);
    1226           2 :         as2js::String input_data_str(input_data);
    1227          37 :         for(size_t idx(0); idx < input_data_str.length(); ++idx)
    1228             :         {
    1229          36 :             as2js::Input::char_t c(str_input->getc());
    1230          36 :             CPPUNIT_ASSERT(c == input_data_str[idx]);
    1231             :             // the input does not know anything about the position
    1232             :             // so it does not change a bit
    1233          36 :             CPPUNIT_ASSERT(str_input->get_position().get_line() == 1);
    1234             :         }
    1235             : 
    1236           2 :         unlink(filename);
    1237             :     }
    1238             : }
    1239             : 
    1240             : 
    1241           1 : void As2JsStreamUnitTests::test_file()
    1242             : {
    1243             :     {
    1244             :         // 1. create a file with some test in it
    1245             :         char filename[256];
    1246           1 :         strncpy(filename, "/tmp/testXXXXXX.js", sizeof(filename));
    1247           1 :         int fd(mkstemps(filename, 3));
    1248           1 :         char const *input_data("This is\nthe\ninput data\nfor the file\n");
    1249           1 :         size_t const len(strlen(input_data));
    1250           1 :         if(write(fd, input_data, len) != static_cast<ssize_t>(len))
    1251             :         {
    1252           0 :             CPPUNIT_ASSERT(!"write failed");
    1253           1 :             return;
    1254             :         }
    1255           1 :         close(fd);
    1256             : 
    1257             :         // 2. put that in a file
    1258           1 :         as2js::FileInput::pointer_t str_input(new as2js::FileInput);
    1259             : 
    1260             :         // test a filename that does not exist
    1261           1 :         CPPUNIT_ASSERT(!str_input->open("I'm pretty sure that this will not work although a funky programmer may end up creating such a file..."));
    1262             :         // filename not modified if open fails
    1263           1 :         CPPUNIT_ASSERT(str_input->get_position().get_filename() == "");
    1264             : 
    1265             :         // expect this open to work
    1266           1 :         CPPUNIT_ASSERT(str_input->open(filename));
    1267             : 
    1268             :         // The filename for the StandardInput is set to "-" by default
    1269           1 :         CPPUNIT_ASSERT(str_input->get_position().get_filename() == filename);
    1270             : 
    1271           1 :         CPPUNIT_ASSERT(str_input->get_position().get_line() == 1);
    1272           2 :         as2js::String input_data_str(input_data);
    1273          37 :         for(size_t idx(0); idx < input_data_str.length(); ++idx)
    1274             :         {
    1275          36 :             as2js::Input::char_t c(str_input->getc());
    1276          36 :             CPPUNIT_ASSERT(c == input_data_str[idx]);
    1277             :             // the input does not know anything about the position
    1278             :             // so it does not change a bit
    1279          36 :             CPPUNIT_ASSERT(str_input->get_position().get_line() == 1);
    1280             :         }
    1281             : 
    1282             :         // if already open, we get a throw
    1283           1 :         CPPUNIT_ASSERT_THROW(str_input->open("This is yet another filename..."), as2js::exception_file_already_open);
    1284           1 :         CPPUNIT_ASSERT(str_input->get_position().get_filename() == filename);
    1285             : 
    1286           2 :         unlink(filename);
    1287             :     }
    1288             : }
    1289             : 
    1290             : 
    1291           1 : void As2JsStreamUnitTests::test_bad_impl()
    1292             : {
    1293             :     {
    1294           4 :         class BadImpl : public as2js::Input
    1295             :         {
    1296             :         public:
    1297             :             // no overloading of either virtual function is a problem!
    1298             :         };
    1299             : 
    1300           1 :         as2js::Input::pointer_t str_input(new BadImpl);
    1301           1 :         CPPUNIT_ASSERT_THROW(str_input->getc(), as2js::exception_internal_error);
    1302             :     }
    1303           1 : }
    1304             : 
    1305             : 
    1306           1 : void As2JsStreamUnitTests::test_stdout()
    1307             : {
    1308             :     {
    1309             :         // 1. create an empty file
    1310             :         char filename[256];
    1311           1 :         strncpy(filename, "/tmp/testXXXXXX.js", sizeof(filename));
    1312           1 :         int fd(mkostemps(filename, 3, O_WRONLY));
    1313             : 
    1314             :         // 2. put that in std::cout
    1315           1 :         if(freopen(filename, "a", stdout) == nullptr)
    1316             :         {
    1317           0 :             CPPUNIT_ASSERT(!"freopen() of stdout failed");
    1318           0 :             return;
    1319             :         }
    1320             : 
    1321             :         // 3. generate some data in the file
    1322           1 :         as2js::String str("This is some test to send to stdout\n");
    1323           1 :         bool assert0(false);
    1324           1 :         bool assert1(false);
    1325           1 :         bool assert2(false);
    1326             :         {
    1327           1 :             as2js::Output::pointer_t output(new as2js::StandardOutput);
    1328             : 
    1329             :             // at the start the position is expected to be 1
    1330             : 
    1331             :             // The filename for the StandardOutput is set to "-" by default
    1332           1 :             assert0 = output->get_position().get_filename() == "-";
    1333             : 
    1334           1 :             assert1 = output->get_position().get_line() == 1;
    1335             : 
    1336           1 :             output->write(str);
    1337             : 
    1338             :             // the write() has no effect over the position
    1339           1 :             assert2 = static_cast<as2js::Output const *>(output.get())->get_position().get_line() == 1;
    1340             :         }
    1341             :         // now StandardOutput is closed, verify the contents of the file
    1342             : 
    1343             :         // 4. reassign the output
    1344             :         //
    1345             :         //    This freopen() works under Linux, on other systems, you may
    1346             :         //    have to fiddle with the code; see:
    1347             :         //    http://stackoverflow.com/questions/1908687/how-to-redirect-the-output-back-to-the-screen-after-freopenout-txt-a-stdo
    1348           1 :         if(freopen("/dev/tty", "a", stdout) == nullptr)
    1349             :         {
    1350           0 :             CPPUNIT_ASSERT(!"freopen() to restore stdout failed");
    1351           0 :             return;
    1352             :         }
    1353             : 
    1354           1 :         CPPUNIT_ASSERT(assert0 && assert1 && assert2); // these are here because stdout is now restored
    1355             : 
    1356           1 :         lseek(fd, 0, SEEK_SET);
    1357             : 
    1358             :         char buf[256];
    1359           1 :         ssize_t l(read(fd, buf, sizeof(buf)));
    1360           1 :         CPPUNIT_ASSERT(l == str.utf8_length());
    1361           1 :         CPPUNIT_ASSERT(static_cast<size_t>(l) < sizeof(buf)); // too large, we cannot continue
    1362           1 :         buf[l] = '\0';
    1363           1 :         CPPUNIT_ASSERT(str == buf);
    1364             : 
    1365           1 :         close(fd);
    1366           1 :         unlink(filename);
    1367             :     }
    1368             : }
    1369             : 
    1370             : 
    1371           2 : void As2JsStreamUnitTests::test_stdout_destructive()
    1372             : {
    1373           2 :     if(as2js_test::g_run_stdout_destructive)
    1374             :     {
    1375             :         // 1. create an empty file
    1376             :         char filename[256];
    1377           1 :         strncpy(filename, "/tmp/testXXXXXX.js", sizeof(filename));
    1378           1 :         int fd(mkostemps(filename, 3, O_WRONLY));
    1379           1 :         close(fd);
    1380             : 
    1381             :         // 2. put that in std::cout
    1382           1 :         if(freopen(filename, "a", stdout) == nullptr)
    1383             :         {
    1384           0 :             CPPUNIT_ASSERT(!"freopen() of stdout failed");
    1385           0 :             return;
    1386             :         }
    1387           1 :         setbuf(stdout, nullptr); // with a buffer the write would not fail!
    1388             : 
    1389             :         // 3. generate some data in the file
    1390           1 :         as2js::String str("This is some test to send to stdout\n");
    1391             :         {
    1392           1 :             as2js::Output::pointer_t output(new as2js::StandardOutput);
    1393             : 
    1394             :             // close stdout before writing to it so we get an error
    1395           1 :             close(fileno(stdout));
    1396             : 
    1397           1 :             CPPUNIT_ASSERT_THROW(output->write(str), as2js::exception_exit);
    1398             :         }
    1399             :         // now StandardOutput is closed, verify the contents of the file
    1400             : 
    1401             :         // 4. reassign the output
    1402             :         //
    1403             :         //    This freopen() fails with error 22 (EINVAL).
    1404             :         //    have to fiddle with the code; see:
    1405             :         //    http://stackoverflow.com/questions/1908687/how-to-redirect-the-output-back-to-the-screen-after-freopenout-txt-a-stdo
    1406           1 :         if(freopen("/dev/tty", "a+", stdout) == nullptr)
    1407             :         {
    1408           0 :             CPPUNIT_ASSERT(!"freopen() of stdout failed");
    1409           0 :             return;
    1410             :         }
    1411             : 
    1412           1 :         unlink(filename);
    1413             :     }
    1414             :     else
    1415             :     {
    1416           1 :         std::cout << " --- test_stdout_destructive() not run, use --destructive on the command line to not bypass this test --- ";
    1417             :     }
    1418             : }
    1419             : 
    1420             : 
    1421           1 : void As2JsStreamUnitTests::test_output()
    1422             : {
    1423             :     {
    1424             :         // 1. create an empty file
    1425           1 :         char const *filename("/tmp/test123456.js");
    1426             : 
    1427             :         // 2. generate some data in the file
    1428           1 :         as2js::String str("This is\nsome test\nto send\nto \"filename\".\n");
    1429             :         {
    1430           1 :             as2js::FileOutput::pointer_t output(new as2js::FileOutput);
    1431             : 
    1432           1 :             CPPUNIT_ASSERT(!output->open("/first/we/want/to/test/with/an/invalid/filename!"));
    1433             : 
    1434           1 :             CPPUNIT_ASSERT(output->open(filename));
    1435             : 
    1436           1 :             CPPUNIT_ASSERT_THROW(output->open("another one"), as2js::exception_file_already_open);
    1437             : 
    1438             :             // at the start the position is expected to be 1
    1439           1 :             CPPUNIT_ASSERT(output->get_position().get_line() == 1);
    1440             : 
    1441             :             // The filename for the FileOutput is set to the file filename as passed to open()
    1442           1 :             CPPUNIT_ASSERT(output->get_position().get_filename() == filename);
    1443             : 
    1444           1 :             CPPUNIT_ASSERT(output->get_position().get_line() == 1);
    1445             : 
    1446           1 :             output->write(str);
    1447             : 
    1448             :             // the write() has no effect over the position
    1449           1 :             CPPUNIT_ASSERT(static_cast<as2js::Output const *>(output.get())->get_position().get_line() == 1);
    1450             :         }
    1451             :         // now FileOutput is closed, verify the contents of the file
    1452             : 
    1453           1 :         int fd(open(filename, O_RDONLY));
    1454             : 
    1455             :         char buf[256];
    1456           1 :         ssize_t l(read(fd, buf, sizeof(buf)));
    1457           1 :         CPPUNIT_ASSERT(l == str.utf8_length());
    1458           1 :         CPPUNIT_ASSERT(static_cast<size_t>(l) < sizeof(buf)); // too large, we cannot continue
    1459           1 :         buf[l] = '\0';
    1460           1 :         CPPUNIT_ASSERT(str == buf);
    1461             : 
    1462           1 :         close(fd);
    1463           1 :         unlink(filename);
    1464             :     }
    1465             : 
    1466             :     {
    1467             :         // 1. create an empty file
    1468           1 :         char const *filename("/tmp/test789012.js");
    1469             : 
    1470             :         // 2. determine the current fd
    1471           1 :         char const *find_fd("/tmp/test345678.js");
    1472           1 :         int fd_to_close(open(find_fd, O_RDWR|O_CREAT, 0600));
    1473           1 :         close(fd_to_close);
    1474           1 :         unlink(find_fd);
    1475             : 
    1476             :         // 3. generate some data in the file
    1477           1 :         as2js::String str("This is\nsome test\nto send\nto \"filename\".\n");
    1478         900 :         while(str.length() < 64 * 1024) // we should get the size from a file created with fopen()... ?
    1479             :         {
    1480         898 :             str += "This string is too short to make sure we get a flush and a write error...";
    1481             :         }
    1482             :         {
    1483           1 :             as2js::FileOutput::pointer_t output(new as2js::FileOutput);
    1484             : 
    1485           1 :             CPPUNIT_ASSERT(!output->open("/first/we/want/to/test/with/an/invalid/filename!"));
    1486             : 
    1487           1 :             CPPUNIT_ASSERT(output->open(filename));
    1488             : 
    1489           1 :             CPPUNIT_ASSERT_THROW(output->open("another one"), as2js::exception_file_already_open);
    1490             : 
    1491             :             // at the start the position is expected to be 1
    1492           1 :             CPPUNIT_ASSERT(output->get_position().get_line() == 1);
    1493             : 
    1494             :             // The filename for the StandardOutput is set to "-" by default
    1495           1 :             CPPUNIT_ASSERT(output->get_position().get_filename() == filename);
    1496             : 
    1497           1 :             CPPUNIT_ASSERT(output->get_position().get_line() == 1);
    1498             : 
    1499             :             // close so we can generate an error...
    1500           1 :             close(fd_to_close);
    1501             : 
    1502           1 :             CPPUNIT_ASSERT_THROW(output->write(str), as2js::exception_exit);
    1503             : 
    1504             :             // the write() has no effect over the position
    1505           1 :             CPPUNIT_ASSERT(static_cast<as2js::Output const *>(output.get())->get_position().get_line() == 1);
    1506             :         }
    1507             :         // now FileOutput is closed, verify the contents of the file
    1508             : 
    1509           1 :         int fd(open(filename, O_RDONLY));
    1510             : 
    1511             :         char buf[256];
    1512           1 :         ssize_t l(read(fd, buf, sizeof(buf)));
    1513           1 :         CPPUNIT_ASSERT(l == 0); // must be empty since it was closed before the write
    1514             : 
    1515           1 :         close(fd);
    1516           1 :         unlink(filename);
    1517             :     }
    1518           1 : }
    1519             : 
    1520             : 
    1521           1 : void As2JsStreamUnitTests::test_string_output()
    1522             : {
    1523             :     {
    1524           1 :         as2js::String str("This is\nsome test\nto send\nto \"filename\".\n");
    1525             : 
    1526           2 :         as2js::StringOutput::pointer_t output(new as2js::StringOutput);
    1527             : 
    1528             :         // at the start the position is expected to be 1
    1529           1 :         CPPUNIT_ASSERT(output->get_position().get_line() == 1);
    1530             : 
    1531             :         // The filename for the StringOutput is always ""
    1532           1 :         CPPUNIT_ASSERT(output->get_position().get_filename() == "");
    1533             : 
    1534           1 :         CPPUNIT_ASSERT(output->get_position().get_line() == 1);
    1535             : 
    1536           1 :         output->write(str);
    1537             : 
    1538             :         // the write() has no effect over the position
    1539           1 :         CPPUNIT_ASSERT(static_cast<as2js::Output const *>(output.get())->get_position().get_line() == 1);
    1540             : 
    1541           1 :         CPPUNIT_ASSERT(output->get_string() == str);
    1542             : 
    1543           1 :         output->write(str);
    1544           2 :         CPPUNIT_ASSERT(output->get_string() == str + str);
    1545             :     }
    1546          13 : }
    1547             : 
    1548             : 
    1549             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10