Changeset 31

Show
Ignore:
Timestamp:
01/29/08 18:20:30 (1 year ago)
Author:
aarti_pl
Message:

- json archive
- improved DUnit (tests updated)
- few refactorings in serializer
- Escaper throws on invalid escape sequence

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/doost/core/Any.d

    r28 r31  
    213213 
    214214unittest { 
    215     startSuite("Any"); 
     215    testSuite.begin("Any"); 
    216216} 
    217217 
     
    227227//------------------------------------------------------------------------------ 
    228228 
    229 unittest { testcase("Any - assigning", { 
     229unittest { testCase.execute("Any - assigning", { 
    230230    bool assigned=false; 
    231231    auto t=new Test; 
     
    254254//------------------------------------------------------------------------------ 
    255255 
    256 unittest { testcase("Any - comparing", { 
     256unittest { testCase.execute("Any - comparing", { 
    257257    auto v = Any(); 
    258258    auto z = Any(); 
     
    267267//------------------------------------------------------------------------------ 
    268268 
    269 unittest { testcase("Any - toString()", { 
     269unittest { testCase.execute("Any - toString()", { 
    270270    auto v = Any(); 
    271271    v=5; 
     
    279279 
    280280unittest { 
    281     finishSuite
    282 } 
     281    testSuite.finish
     282} 
  • trunk/doost/text/Escaper.d

    r28 r31  
    88 
    99//TODO: add other escape sequences from: http://www.digitalmars.com/d/lex.html 
     10 
     11 
     12class UnescapeException : Exception { 
     13    this(string str) { 
     14        super(str); 
     15    } 
     16} 
    1017 
    1118/******************************************************************************* 
     
    5764                case 't'  : result ~= '\t'; break; 
    5865                case 'v'  : result ~= '\v'; break; 
    59                 default: result ~= c
     66                default: throw new UnescapeException("Illegal escape character")
    6067            } 
    6168            isEscape=false; 
  • trunk/doost/util/DUnit.d

    r28 r31  
    2323import std.date; 
    2424import std2.traits; 
    25  
    26 //------------------------------------------------------------------------------ 
    27  
    28 struct TestCase { 
    29     string name; 
    30 
    31  
    32 struct Trace { 
     25import std2.conv; 
     26 
     27import doost.core.Traits; 
     28 
     29//------------------------------------------------------------------------------ 
     30 
     31enum Align {Left, Center, Right} 
     32 
     33//------------------------------------------------------------------------------ 
     34 
     35interface Element { 
     36    string pattern(); 
     37    string render(string val); 
     38
     39 
     40//------------------------------------------------------------------------------ 
     41 
     42class CellElem : Element { 
     43public: 
     44    this(uint rwidth, Align aligning, string form="%s", uint border = 1) { 
     45        m_cwidth = rwidth; 
     46        m_aligning = aligning; 
     47        m_border = border; 
     48        m_form = form; 
     49    } 
     50 
     51    override string pattern() { 
     52        return m_form; 
     53    } 
     54 
     55    override string render(string content) { 
     56        string result; 
     57 
     58        result~=repeat(" ", m_border); 
     59        if (content.length + 2*m_border > m_cwidth) { 
     60            content = content[0.. m_cwidth-2*m_border -1] ~ "."; 
     61        } 
     62 
     63        uint clen = content.length + 2*m_border; 
     64 
     65        if (m_aligning == Align.Left) { 
     66            result~=content; 
     67            result~=repeat(" ", m_cwidth - clen); 
     68        } else 
     69        if (m_aligning == Align.Right) { 
     70            result~=repeat(" ", m_cwidth - clen); 
     71            result~=content; 
     72        } else 
     73        if (m_aligning == Align.Center) { 
     74            uint empty = m_cwidth - clen; 
     75            result~=repeat(" ", empty / 2); 
     76            result~=content; 
     77            result~=repeat(" ", empty - empty / 2); 
     78        } 
     79 
     80        result~=repeat(" ", m_border); 
     81        return result; 
     82    } 
     83 
     84private: 
     85    uint m_cwidth; 
     86    Align m_aligning; 
     87    uint m_border; 
     88    string m_form; 
     89
     90 
     91//------------------------------------------------------------------------------ 
     92 
     93class SepElem : Element { 
     94public: 
     95    this(string form="|") { 
     96        m_form = form; 
     97    } 
     98    override string pattern() { 
     99        return m_form; 
     100    } 
     101    override string render(string str) { 
     102        return str; 
     103    } 
     104private: 
     105    string m_form; 
     106
     107 
     108//------------------------------------------------------------------------------ 
     109 
     110class HlElem : CellElem { 
     111public: 
     112    this(string form="-") { 
     113        super(-1, Align.Left, form, 1); 
     114    } 
     115    override string pattern() { 
     116        return m_form; 
     117    } 
     118    override string render(string str) { 
     119        return repeat(" ", m_border) ~ repeat(m_form, m_cwidth-2*m_border) ~ repeat(" ", m_border); 
     120    } 
     121
     122 
     123//------------------------------------------------------------------------------ 
     124 
     125alias Element[] Row; 
     126 
     127//TODO: struktura Row, i opAssign(Element[] val); w czasie przypisania sÄ 
     128 
     129//obliczane rozmiary kolumn 
     130 
     131//------------------------------------------------------------------------------ 
     132Element Sep(string form = "|") { 
     133    return new SepElem(form); 
     134
     135 
     136//------------------------------------------------------------------------------ 
     137 
     138Element Cell(uint rwidth, Align aligning, string form="%s", uint border = 1) { 
     139    return new CellElem(rwidth, aligning, form, border); 
     140
     141 
     142//------------------------------------------------------------------------------ 
     143 
     144Element Hl(string form="-") { 
     145    return new HlElem(form); 
     146
     147 
     148//------------------------------------------------------------------------------ 
     149 
     150class Table { 
     151public: 
     152    this(uint width = 75) { 
     153        m_width = width; 
     154    } 
     155 
     156    void render(T...)(Row r, T param) { 
     157        uint scount; // number of separators 
     158        uint ccount; // number of cells 
     159        string onerow; //one row 
     160        uint clen; //content length + borders 
     161        uint defwidth; 
     162        CellElem dyncol; 
     163        uint pos; 
     164 
     165 
     166        foreach(e; r) { 
     167            if (cast(SepElem)e) scount++; 
     168            if (auto elem = cast(CellElem)e) { 
     169                ccount++; 
     170                if (elem.m_cwidth == -1) { 
     171                    if (dyncol !is null) throw new Exception("Only one column can have dynamic width"); 
     172                    dyncol = elem; 
     173                } else defwidth+=elem.m_cwidth; 
     174            } 
     175        } 
     176 
     177        if (defwidth + scount>m_width) throw new Exception("Columns have more than 100% width"); 
     178        if (dyncol !is null) { 
     179            dyncol.m_cwidth = m_width - defwidth - scount; 
     180            if (dyncol.m_cwidth<dyncol.m_border*2+1) throw new Exception("Dynamic column is too narrow!"); 
     181        } 
     182 
     183        string content; 
     184        foreach(i, e; r) { 
     185            if (argNumberToMunch(e.pattern) > 0) { 
     186                content = ""; 
     187                foreach(j, v; param) { 
     188                    if (j == pos) { 
     189                        content = format(e.pattern, v); 
     190                        pos++; 
     191                        break; 
     192                    } 
     193                } 
     194            } else content = e.pattern; 
     195 
     196            onerow ~= e.render(content); 
     197        } 
     198 
     199        if (pos < param.length) throw new Exception("Not all tokens consumed!"); 
     200 
     201        writefln("%s", onerow); 
     202    } 
     203 
     204private: 
     205    uint argNumberToMunch(string p) { 
     206        return count(p, "%") - 2*count(p, "%%"); 
     207    } 
     208 
     209    uint m_width; 
     210
     211 
     212unittest { 
     213    auto p = new Table; 
     214    assert(p.argNumberToMunch("%% %% %% %% %") == 1); 
     215    assert(p.argNumberToMunch("% %% % %% %") == 3); 
     216 
     217
     218 
     219//------------------------------------------------------------------------------ 
     220 
     221struct TraceInfo { 
    33222    string trace; 
    34223    long line; 
     
    36225} 
    37226 
    38 struct Failure { 
    39     string error; 
    40 } 
    41  
    42 //------------------------------------------------------------------------------ 
    43  
    44 string ctfe_repeat(string s, uint count) { 
    45     string result; 
    46     for(uint i=0; i<count; i++) result~=s; 
    47     return result; 
    48 } 
    49  
    50 string ctfe_ulongTostring(ulong value) { 
    51     string result; 
    52     ulong divider = 10_000_000_000_000_000_000UL; 
    53     while (divider>value) divider/=10; 
    54  
    55     do { 
    56         result ~= cast(char)value / divider + 48; 
    57         value -= (value / divider) * divider; 
    58     } while ((divider /= 10)!=0) 
    59  
    60     return result; 
    61 } 
    62227 
    63228//------------------------------------------------------------------------------ 
    64229//TODO: pod linuxem nie moÅŒna złapać "segmentation fault", tylko program się wykłada 
    65  
    66 //TODO: traces are not connected with failures; should be stored separately 
    67 //posibility to show traces only on failure 
    68  
    69 TestCase[uint] testcases; 
    70 Trace[][uint] traces; 
    71 Failure[uint] failed; 
    72  
    73 uint tc_counter, tc_fcounter; 
    74 void delegate() setUp, tearDown; 
    75 d_time starttime, elapsedtime; 
    76  
    77  
    78 const table_width = 70; 
    79 const table_col1_width = 3; 
    80 const table_col3_width = 6; 
    81 const table_col2_width = table_width - table_col1_width - table_col3_width - 5; 
    82  
    83 const table_hr = " " ~ ctfe_repeat("-", table_width-2) ~ " "; 
    84  
    85 const table_simple = "|%-"~ ctfe_ulongTostring(table_width-2) ~"s|"; 
    86 const table_tc_col1 = "|%"~ ctfe_ulongTostring(table_col1_width) ~"d."; 
    87 const table_tc_col2 = " %-"~ ctfe_ulongTostring(table_col2_width) ~"s"; 
    88 const table_tc_col3 = "%"~ ctfe_ulongTostring(table_col3_width) ~"s |"; 
    89  
    90 const table_stat_all  = "|  - all    : %-3d" ~ ctfe_repeat(" ", table_width-18) ~"|"; 
    91 const table_stat_pass = "|  - passed : %-3d (%6.2f%%)" ~ ctfe_repeat(" ", table_width-28) ~"|"; 
    92 const table_stat_fail = "|  - failed : %-3d (%6.2f%%)" ~ ctfe_repeat(" ", table_width-28) ~"|"; 
    93  
    94 const table_fail_row1 = "|%3d. %-"~ ctfe_ulongTostring(table_width-7) ~"s|"; 
    95 const table_fail_row2 = "|     %-"~ ctfe_ulongTostring(table_width-7) ~"s|"; 
    96  
    97 //TODO: lepsze funkcje do wydruku tabeli (bardziej uniwersalne) 
    98 //moÅŒe wystarczy tylko usuwać z ciÄ 
    99 gu formatujÄ 
    100 cego wszystkie spacje? np. 
    101 //wydruk nie tylko na ekran, ale takÅŒe do pliku + do kilku źródeł 
    102  
    103  
    104 //  ----------------------------------------------- 
    105 // | * test suite...      | Status | Count | Time  | 
    106 //  ----------------------------------------------- 
    107 // |*    |*               |       *|     * |   *   | 
    108 //  ----------------------------------------------- 
    109 // | Traces:                                       | 
    110 // |                                               | 
    111 //  ----------------------------------------------- 
    112  
    113 //------------------------------------------------------------------------------ 
    114  
    115 //TODO: ewentualnie dodawanie setup i teardown w osobnych funkcjach, ale 
    116230//TODO: co z wielowÄ 
    117231tkowościĠ
    118232? 
    119  
    120 void startSuite(char[] name, void delegate() setup=null, void delegate() teardown=null) { 
    121     failed = null; 
    122     tc_counter = 0; 
    123     tc_fcounter = 0; 
    124     setUp = setup; 
    125     tearDown = teardown; 
    126     writefln(table_hr); 
    127     writefln(table_simple, " " ~ name ~ " test suite."); 
    128     writefln(table_hr); 
    129 } 
    130  
    131233//TODO: add function startGroup/finishGroup 
     234 
     235//------------------------------------------------------------------------------ 
     236 
     237class TestCase { 
     238public: 
     239    void execute(string testname, void delegate() dg) { 
     240        m_testname = testname; 
     241        m_passed = false; 
     242        m_elapsedtime = real.nan; 
     243 
     244        int no; 
     245        string result; 
     246 
     247        if (m_repeat != 0) { 
     248            no = m_repeat; 
     249            m_owner.m_tccounter++; 
     250            m_number = m_owner.m_tccounter; 
     251            try { 
     252                d_time starttime = getUTCtime(); 
     253                for(uint i = 0; i<m_repeat; i++) { 
     254                    if (m_setup !is null) m_setup(); 
     255                    dg(); 
     256                    if (m_teardown !is null) m_teardown(); 
     257                } 
     258                m_elapsedtime = (cast(real)(getUTCtime() - starttime))/1000; 
     259                result = "OK"; 
     260                m_passed = true; 
     261            } 
     262            catch(Exception e) { 
     263                result = "FAIL"; 
     264                m_error = e.toString; 
     265                m_owner.m_tcfcounter++; 
     266                m_owner.m_tcfailed~=this; 
     267                no = 0; 
     268            } 
     269        } else result = "DISABLED"; 
     270 
     271        string tc_no; 
     272        if (m_repeat == 0) {tc_no = "-- "; no = 0; } 
     273            else tc_no = to!(string)(m_owner.m_tccounter) ~ "."; 
     274 
     275        if (m_dotiming) m_owner.table.render(m_owner.tc_tim, tc_no, m_testname ~ " test...", result, no, m_elapsedtime); 
     276            else m_owner.table.render(m_owner.tc, tc_no, m_testname ~ " test...", result); 
     277 
     278        if (m_elapsedtime !is real.nan) m_owner.m_elapsedtime+=m_elapsedtime; 
     279    } 
     280 
     281    TestCase setUp(void delegate() setup) { 
     282        m_setup = setup; 
     283        return this; 
     284    } 
     285 
     286    TestCase tearDown(void delegate() teardown) { 
     287        m_teardown = teardown; 
     288        return this; 
     289    } 
     290 
     291    TestCase repeat(uint count) { 
     292        m_repeat = count; 
     293        return this; 
     294    } 
     295 
     296    TestCase disable() { 
     297        m_repeat = 0; 
     298        return this; 
     299    } 
     300 
     301    TestCase traces() { 
     302        m_dotraces = true; 
     303        m_owner.m_reqtraces = true; 
     304        return this; 
     305    } 
     306 
     307private: 
     308    this(TestSuite owner) { 
     309        m_owner = owner; 
     310    } 
     311 
     312    void printTraces() { 
     313        string lastfile = ""; 
     314        foreach(t; m_traces) { 
     315            if (t.file != lastfile) { 
     316                m_owner.table.render(m_owner.simple); 
     317                if (t.file != "") m_owner.table.render(m_owner.simple, "     " ~ getBaseName(t.file) ~ ":"); 
     318                    else m_owner.table.render(m_owner.simple); 
     319                lastfile = t.file; 
     320            } 
     321 
     322            if (t.line !=0) m_owner.table.render(m_owner.simple, "     " ~ format("%4d:  %s", t.line, t.trace)); 
     323                else m_owner.table.render(m_owner.simple, "     " ~ t.trace); 
     324        } 
     325    } 
     326 
     327 
     328    string m_testname; 
     329    uint m_repeat = 1; 
     330    void delegate() m_setup; 
     331    void delegate() m_teardown; 
     332 
     333    TraceInfo[] m_traces; 
     334    string m_error; 
     335    bool m_passed; 
     336    bool m_dotiming; 
     337    bool m_dotraces; 
     338 
     339    real m_elapsedtime; 
     340    uint m_number; 
     341    TestSuite m_owner; 
     342 
     343} 
     344 
     345//------------------------------------------------------------------------------ 
     346 
     347class TestGroup { 
     348public: 
     349    void begin(string groupname="") { 
     350        m_groupname = groupname; 
     351        if (groupname != "") { 
     352            //m_owner.table.render(m_owner.simple); 
     353            /*if (!first)*/ m_owner.table.render(m_owner.hl); 
     354            m_owner.table.render(m_owner.simple, "Group: " ~ groupname); 
     355            /*if (!last)*/ //m_owner.table.render(m_owner.hl); 
     356        } 
     357    } 
     358 
     359    void finish() { 
     360 
     361    } 
     362 
     363    TestGroup setUp(void delegate() setup) { 
     364        m_setup = setup; 
     365        return this; 
     366    } 
     367 
     368    TestGroup tearDown(void delegate() teardown) { 
     369        m_teardown = teardown; 
     370        return this; 
     371    } 
     372 
     373    TestGroup repeat(uint count) { 
     374        m_repeat = count; 
     375        return this; 
     376    } 
     377 
     378    TestGroup disable() { 
     379        m_repeat = 0; 
     380        return this; 
     381    } 
     382 
     383private: 
     384    this(TestSuite owner) { 
     385        m_owner = owner; 
     386    } 
     387 
     388    string m_groupname; 
     389    uint m_repeat = 1; 
     390    void delegate() m_setup; 
     391    void delegate() m_teardown; 
     392    bool m_dotiming; 
     393    bool m_dotraces; 
     394 
     395    TestSuite m_owner; 
     396} 
     397 
     398//------------------------------------------------------------------------------ 
     399 
     400class TestSuite { 
     401public: 
     402    //TODO: function disable, which sets repeat to 0 
     403    //TODO: tylko jeden otwarty test suite jednocześnie. 
     404    //jeÅŒeli ktoś próbuje otworzyć drugi to musi czekać na skończenie pierwszego?? 
     405    //jeÅŒeli na tym samym threadzie, to po prostu błĠ
     406d 
     407 
     408    void begin(string suitename) { 
     409        m_suitename = suitename; 
     410        m_tccounter = 0; 
     411        m_tcfcounter = 0; 
     412 
     413        table.render(hl); 
     414        table.render(title, m_suitename ~ " test suite."); 
     415        //table.render(hl); 
     416    } 
     417 
     418    void finish() { 
     419        uint tcpcounter = m_tccounter - m_tcfcounter; 
     420 
     421        if (m_tcfailed.length>0) { 
     422            table.render(hl); 
     423            table.render(simple, "Failed test cases / errors / traces:"); 
     424            table.render(simple); 
     425            foreach(tc; m_tcfailed) { 
     426                table.render(fail, tc.m_number, tc.m_testname); 
     427                table.render(simple, "     " ~ tc.m_error); 
     428                table.render(simple); 
     429                tc.printTraces; 
     430            } 
     431 
     432        } 
     433 
     434        if (m_dotraces || m_reqtraces) { 
     435            table.render(hl); 
     436            table.render(simple, "Traces:"); 
     437            table.render(simple); 
     438            foreach(tc; m_testcases) { 
     439                if (tc.m_repeat == 0 || tc.m_dotraces == false) continue; 
     440                table.render(fail, tc.m_number, tc.m_testname); 
     441                tc.printTraces; 
     442                table.render(simple); 
     443            } 
     444        } 
     445 
     446        table.render(hl); 
     447        table.render(simple); 
     448        table.render(etime,  "Statistics :", "Total time :", m_elapsedtime); 
     449        table.render(stat,  " -    all  :", m_tccounter); 
     450        table.render(stat,  " - passed  :", tcpcounter, cast(double)(tcpcounter*100)/m_tccounter); 
     451        table.render(stat,  " - failed  :", m_tcfcounter, cast(double)(m_tcfcounter*100)/m_tccounter); 
     452        table.render(hl); 
     453 
     454    } 
     455 
     456    TestSuite setUp(void delegate() setup) { 
     457        m_setup = setup; 
     458        return this; 
     459    } 
     460 
     461    TestSuite tearDown(void delegate() teardown) { 
     462        m_teardown = teardown; 
     463        return this; 
     464    } 
     465 
     466    TestSuite timing() { 
     467        m_dotiming = true; 
     468        return this; 
     469    } 
     470 
     471    TestSuite traces() { 
     472        m_dotraces = true; 
     473        return this; 
     474    } 
     475 
     476    TestSuite repeat(uint count) { 
     477        m_repeat = count; 
     478        return this; 
     479    } 
     480 
     481    TestSuite disable() { 
     482        m_repeat = 0; 
     483        return this; 
     484    } 
     485 
     486    TestSuite width(uint w) { 
     487        table.m_width = w; 
     488        return this; 
     489    } 
     490 
     491private: 
     492    /*************************************************************************** 
     493        Private constructor to avoid creating suites from outside 
     494     **************************************************************************/ 
     495    this() { 
     496        table = new Table; 
     497 
     498        title   = [Sep, Cell(-1, Align.Center), Sep]; 
     499        tc      = [Sep, Cell(5, Align.Right, "%-s", 0), Cell(-1, Align.Left), Cell(7, Align.Right), Sep]; 
     500        tc_tim  = [Sep, Cell(5, Align.Right, "%-s", 0), Cell(-1, Align.Left), Cell(7, Align.Right), Sep, Cell(8, Align.Right), Sep, Cell(8, Align.Right, "%6.2f"), Sep]; 
     501        simple  = [Sep, Cell(-1, Align.Left), Sep]; 
     502        etime   = [Sep, Cell(15, Align.Right), Cell(-1, Align.Right), Cell(10, Align.Left, "%6.4f s"), Sep]; 
     503        stat    = [Sep, Cell(15, Align.Right), Cell(6, Align.Left), Cell(-1, Align.Left, "(%6.2f %%)"), Sep]; 
     504        fail    = [Sep, Cell(5, Align.Right, "%d."), Cell(-1, Align.Left), Sep]; 
     505        hl      = [Hl]; 
     506 
     507    } 
     508 
     509    /*************************************************************************** 
     510     **************************************************************************/ 
     511    TestGroup createGroup() { 
     512        auto tg = new TestGroup(this); 
     513        tg.repeat(m_repeat); 
     514        tg.setUp(m_setup); 
     515        tg.tearDown(m_teardown); 
     516        tg.m_dotiming = m_dotiming; 
     517        tg.m_dotraces = m_dotraces; 
     518        m_testgroups~=tg; 
     519        m_curgroup = tg; 
     520        m_firstingroup = true; 
     521        return tg; 
     522    } 
     523 
     524    TestCase createCase() { 
     525        auto tc = new TestCase(this); 
     526        if (m_curgroup !is null) { 
     527            tc.repeat(m_curgroup.m_repeat); 
     528            tc.setUp(m_curgroup.m_setup); 
     529            tc.tearDown(m_curgroup.m_teardown); 
     530            tc.m_dotiming = m_curgroup.m_dotiming; 
     531            tc.m_dotraces = m_dotraces; 
     532        } else { 
     533            tc.repeat(m_repeat); 
     534            tc.setUp(m_setup); 
     535            tc.tearDown(m_teardown); 
     536            tc.m_dotiming = m_dotiming; 
     537            tc.m_dotraces = m_dotraces; 
     538        } 
     539 
     540        if (m_firstingroup) {table.render(hl); m_firstingroup=false;} 
     541        m_testcases~=tc; 
     542        m_curcase = tc; 
     543        return m_testcases[$-1]; 
     544    } 
     545 
     546    Table table; 
     547    Row title, tc, tc_tim, simple, etime, stat, fail, hl; 
     548 
     549    void delegate() m_setup; 
     550    void delegate() m_teardown; 
     551    bool m_dotiming; 
     552    bool m_dotraces; 
     553    bool m_reqtraces; 
     554    string m_suitename; 
     555    uint m_repeat = 1; 
     556    bool m_firstingroup=true; 
     557 
     558    TestCase m_curcase; 
     559    TestCase[] m_testcases; 
     560    TestCase[] m_tcfailed; 
     561    TestGroup m_curgroup; 
     562    TestGroup[] m_testgroups; 
     563    real m_elapsedtime=0; 
     564 
     565    uint m_tccounter, m_tcfcounter; 
     566} 
    132567 
    133568//------------------------------------------------------------------------------ 
     
    164599 
    165600//------------------------------------------------------------------------------ 
     601 
     602bool isNan(real x) { 
     603    if (x is real.nan) return true; 
     604    return false; 
     605} 
     606 
     607bool compareFloats(T)(T first, T second) { 
     608    trace(first, "  ??  ", second); 
     609    if (isNan(first) || isNaN(second)) { 
     610        return isNaN(first) && isNaN(second); 
     611    } 
     612    return first == second; 
     613} 
     614 
     615bool compareRefs(T)(T first, T second) { 
     616    trace(first, "  ??  ", second); 
     617    if (first is null || second is null) { 
     618        return first is second; 
     619    } 
     620    return cast(bool)(first == second); 
     621} 
     622 
     623//------------------------------------------------------------------------------ 
    166624//TODO: don't work for all types e.g. pointers 
    167625bool compareArrays(T)(T first, T second) { 
    168626    static assert(isArray!(T), "Template function can compare only arrays"); 
     627    alias arrayElementType!(T) ElemType; 
    169628 
    170629    if (first.length != second.length) return false; 
    171630 
     631    bool res = true; 
    172632    foreach(i, v; first) { 
    173         if (v is null || second[i] is null) { 
    174             if (v !is second[i]) return false; 
    175             continue; 
    176         } 
    177         if (v != second[i]) return false; 
    178     } 
    179  
    180     return true; 
    181 
    182  
    183 //------------------------------------------------------------------------------ 
    184  
    185 void testcase(string name, void delegate() dg, uint number = 1) { 
    186     tc_counter++; 
    187     testcases[tc_counter] = TestCase(name); 
    188     writef(table_tc_col1, tc_counter); 
    189     writef(table_tc_col2, name ~ " test..."); 
    190     try { 
    191         //TODO: add timing of every test case 
    192         d_time starttime = getUTCtime(); 
    193         for(uint i = 0; i<number; i++) { 
    194             if (setUp !is null) setUp(); 
    195             dg(); 
    196             if (tearDown !is null) tearDown(); 
    197         } 
    198         d_time elapsedtime = getUTCtime() - starttime; 
    199  
    200         writefln(table_tc_col3, "OK"); 
    201     } 
    202     catch(Exception e) { 
    203         writefln(table_tc_col3, "FAIL"); 
    204         tc_fcounter++; 
    205         failed[tc_counter] = Failure(e.toString); 
    206     } 
     633        static if (is(ElemType TYPE == TYPE*) || is(ElemType == class)) { 
     634            res = compareRefs(v, second[i]); 
     635        } else 
     636        static if (is(ElemType == float) || is(ElemType == double) || is(ElemType == real)) { 
     637            res = compareFloats(v, second[i]); 
     638        } else 
     639        static assert("Don't know how to compare arrays."); 
     640 
     641        if (res == false) break; 
     642    } 
     643 
     644    return res; 
     645
     646 
     647//------------------------------------------------------------------------------ 
     648 
     649TestSuite suite; 
     650 
     651TestSuite testSuite() { 
     652    if (suite is null) suite = new TestSuite; 
     653    return suite; 
     654
     655 
     656TestGroup testGroup() { 
     657    assert(suite !is null, "You have to start suite before creating test group!"); 
     658    return suite.createGroup; 
     659
     660 
     661TestCase testCase() { 
     662    assert(suite !is null, "You have to start suite before creating test case!"); 
     663    return suite.createCase; 
    207664} 
    208665 
     
    210667//TODO: add versions without file and line 
    211668//TODO: unit testy tylko w wersji debug 
    212 //------------------------------------------------------------------------------ 
    213  
    214 void tracefl(T...)(string file, long line, T params) { 
    215     debug traces[tc_counter] ~= Trace(format(params), line, file); 
    216 } 
    217  
    218 //------------------------------------------------------------------------------ 
    219  
    220 void trace(T...)(T params) { 
    221     debug traces[tc_counter] ~= Trace(format(params)); 
    222 } 
    223  
    224 //------------------------------------------------------------------------------ 
    225  
    226 private void printTraces(uint no) { 
    227     string lastfile = ""; 
    228     foreach(t; traces[no]) { 
    229         if (t.file != lastfile) { 
    230             writefln(table_simple, " "); 
    231             if (t.file != "") writefln(table_fail_row2, getBaseName(t.file) ~ ":"); 
    232                 else writefln(table_simple, " "); 
    233             lastfile = t.file; 
    234         } 
    235  
    236         if (t.line !=0) writefln(table_fail_row2, format("%4d:  %s", t.line, t.trace)); 
    237             else writefln(table_fail_row2, format("%s", t.trace)); 
    238     } 
    239 } 
    240  
    241669//TODO: funkcja porównujĠ
    242670ca dwie tablice wartości/referencji 
    243  
    244 //------------------------------------------------------------------------------ 
    245 enum {TIMING=1, TRACES=2} 
    246  
    247 void finishSuite(int params=0) { 
    248     uint tc_pcounter = tc_counter - tc_fcounter; 
    249  
    250     if (failed.length>0) { 
    251         writefln(table_hr); 
    252         writefln(table_simple, " Failed test cases / errors / traces:"); 
    253         writefln(table_simple, " "); 
    254         foreach(k, v; failed) { 
    255             writefln(table_fail_row1, k, testcases[k].name); 
    256             writefln(table_fail_row2, failed[k].error); 
    257             writefln(table_simple, " "); 
    258             if (k in traces) { 
    259                 printTraces(k); 
    260                 writefln(table_simple, " "); 
    261             } 
    262         } 
    263     } 
    264  
    265     if (params && TRACES && traces.length>0) { 
    266         writefln(table_hr); 
    267         writefln(table_simple, " Traces:"); 
    268         writefln(table_simple, " "); 
    269         foreach(no, val; traces) { 
    270             writefln(table_fail_row1, no, testcases[no].name); 
    271             printTraces(no); 
    272             writefln(table_simple, " "); 
    273         } 
    274     } 
    275  
    276     writefln(table_hr); 
    277     writefln(table_simple, " Statistics:"); 
    278     writefln(table_stat_all, tc_counter); 
    279     writefln(table_stat_pass, tc_pcounter, cast(double)(tc_pcounter*100)/tc_counter); 
    280     writefln(table_stat_fail, tc_fcounter, cast(double)(tc_fcounter*100)/tc_counter); 
    281     writefln(table_hr); 
    282     writefln; 
    283     writefln; 
    284 
     671//------------------------------------------------------------------------------ 
     672 
     673void tracefl(T...)(string file, long line, T params) { 
     674    debug { 
     675        if (suite is null) return; 
     676        if (suite.m_curcase is null) return; 
     677        suite.m_curcase.m_traces ~= TraceInfo(format(params), line, file); 
     678    } 
     679
     680 
     681//------------------------------------------------------------------------------ 
     682 
     683void trace(T...)(T params) { 
     684    debug { 
     685        if (suite is null) return; 
     686        if (suite.m_curcase is null) return; 
     687        suite.m_curcase.m_traces ~= TraceInfo(format(params)); 
     688    } 
     689
  • trunk/doost/util/serializer/Registry.d

    r28 r31  
    175175 
    176176/******************************************************************************* 
    177     All classes stored in Registry must iherit from Registry interface 
     177    All classes stored in Registry must inherit from Registry interface 
    178178 ******************************************************************************/ 
    179179interface Registration { 
  • trunk/doost/util/serializer/Serializer.d

    r28 r31  
    7878//------------------------------------------------------------------------------ 
    7979 
    80 //BUG: not possible. Why? 
    81 //class Serializer(alias T...) 
     80//ENH: not possible - why?: class Serializer(alias T...) 
    8281//ENH: lack of static access to some member of templates without instantiation needed 
    8382//BUG: inner class Archive is invisible in default parameter of template 
    84 class Serializer(alias ARCHIVE, STORAGE=string) { 
     83class Serializer(alias CONCRETEARCHIVE, STORAGE=string) { 
    8584//ENH: when parameter of function is preceeding by alias, stringof on this parameter 
    8685//should give original name of symbol 
    8786 
    8887private: 
     88    const info = "Type '" ~ STORAGE.stringof ~ "' does not meet Storage requirements: "; 
     89    static assert(is(typeof(STORAGE.init) == STORAGE), info ~ "lack of init() method."); 
     90    static assert(is(typeof(STORAGE.dup) == STORAGE), info ~ "lack of dup() method."); 
     91 
    8992    enum Mode {LOAD, DUMP} 
    90  
    91     mixin ARCHIVE!(Archive); 
     93    mixin CONCRETEARCHIVE!(Archive); 
    9294 
    9395    static synchronized Archive m_archive; 
     
    105107        init(m_archive); 
    106108    } 
    107     //TODO: dorobić JSONArchive 
    108109 
    109110    /*************************************************************************** 
     
    201202 
    202203        //Eventual additional operations ... at begining of traverse... 
    203         //BUG: SFINAE should fail on syntax errors... 
     204        //BUG: SFINAE should fail on syntax errors... Currently simple syntax errors 
     205        //are very difficult to catch 
    204206        static if (is(typeof(begin!(VALUE)(value, archive)) == bool)) { 
    205207            begin!(VALUE)(value, archive); 
     
    273275        } else 
    274276        //Other built-in types 
     277        //TODO: rozbić isAtomic na Integral i Floating i Char 
    275278        static if (isAtomic!(VALUE)) { 
    276279            if (archive.mode == Mode.LOAD) return loadAtomic(value, archive); 
     
    284287    } 
    285288 
     289    //TODO: move checking for version and functions inside user UDT into 
     290    //serializer from Archive. How? 
     291 
     292    /*************************************************************************** 
     293     **************************************************************************/ 
     294    bool attendFields(VALUE)(ref VALUE value, Archive archive) { 
     295        //Load function exists 
     296        static if ( is(typeof(&value.loadUdt!(Archive)) == void delegate(Archive))) { 
     297            if (archive.mode == Mode.LOAD) {value.loadUdt(archive); return true;} 
     298        } 
     299        //Dump function exists 
     300        static if ( is(typeof(&value.dumpUdt!(Archive)) == void delegate(Archive))) { 
     301            if (archive.mode == Mode.DUMP) {value.dumpUdt(archive); return true;} 
     302        } 
     303        //TODO: moÅŒna zmniejszyć wielkość funkcji przez sprawdzenie, czy obie powyÅŒsze 
     304        //funkcje udało się zainstancjować. jeÅŒeli tak to poniÅŒsze nie musi być wstawiane 
     305 
     306        //Exists describe function 
     307        static if ( is(typeof(&value.describeUdt!(Archive)) == void delegate(Archive))) { 
     308            value.describeUdt(archive); 
     309        } else 
     310        //All fields are visible 
     311        static if (areUdtFieldsVisible!(VALUE)) { 
     312            foreach(i, v; value.tupleof) { 
     313                if (archive.mode == Mode.LOAD) { 
     314                    normalizedType!(typeof(v)) elem; 
     315                    loadOneField(elem, value.tupleof[i].stringof, archive); 
     316                    checkType!(typeof(v))(elem); 
     317 
     318                    static if (isStaticArray!(typeof(v))) { 
     319                        foreach(n, saval; value.tupleof[i]) value.tupleof[i][n] = elem[n]; 
     320                    } else { 
     321                        value.tupleof[i]= elem; 
     322                    } 
     323 
     324                } else { 
     325                    normalizedType!(typeof(v)) elem = v; 
     326                    dumpOneField(elem, value.tupleof[i].stringof, archive); 
     327                } 
     328            } 
     329        } else { 
     330            //FIXME: 
     331            static assert(false, "UDT '" ~ VALUE.stringof ~ "' is not serializable."); 
     332        } 
     333 
     334        return true; 
     335    } 
     336 
     337 
     338    /*************************************************************************** 
     339        Returns: true if class was imported by this function 
     340     **************************************************************************/ 
     341    bool attendVersion(VALUE)(ref VALUE value, Archive archive, uint stored_ver) { 
     342        if (stored_ver > 0) { 
     343            uint defined_ver = 0; 
     344            //more important is version in registry; it allows to override 
     345            //mistakenly defined versions in classes... 
     346            static if (is(typeof((cast(VALUE)value).versionUdt) == uint)) { 
     347                defined_ver = (cast(VALUE)value).versionUdt; 
     348            } 
     349            if (auto peek = archive.registry.peek!(TypeDescription, VALUE)) { 
     350                uint ver = peek.ver; 
     351                if (ver>0) defined_ver = ver; 
     352            } 
     353            if (stored_ver != defined_ver && defined_ver>0) { 
     354                static if ( is(typeof(&value.importUdt!(Archive)) == void delegate(ref VALUE, Archive, uint))) { 
     355                    //FIXME: przy imporcie pola nie będÄ 
     356 zparsowane??? (JSON) 
     357                    value.importUdt(value, archive, stored_ver); 
     358                    return true; 
     359                } else { 
     360                    throw new SerializerException("Udt version in storage is different than in program"); 
     361                } 
     362            } 
     363        } 
     364        return false; 
     365    } 
     366 
     367 
    286368//------------------------------------------------------------------------------ 
    287369 
     
    292374        //BUG: private attribute is not applied to template functions 
    293375 
     376        //Bug - jak sprawdzić czy poniÅŒsze jest zdefiniowane? 
     377        mixin ArchiveExt; 
     378 
    294379        this() { 
    295380            registry = new Registry; 
     
    299384        Registry registry; 
    300385 
    301