root/OpenSceneGraph/trunk/examples/osgunittests/UnitTestFramework.cpp @ 6783

Revision 6783, 8.6 kB (checked in by robert, 7 years ago)

From Olar Flebbe, "Visual Studio 2005 triggered a small glitch in UnittestFramework?.cpp

Do not derefence it2 if it is at end()."

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13#include "UnitTestFramework.h"
14
15#include <algorithm>
16
17namespace osgUtx
18{
19
20//////////////////////////////////////////////////////////////////////////////
21
22TestContext::TestContext()
23{
24}
25
26void TestContext::setTraceLevel(TraceLevel tl)
27{
28    _tout.setTraceLevel(tl);
29}
30
31TestContext::TraceLevel TestContext::getTraceLevel() const
32{
33    return _tout.getTraceLevel();
34}
35
36std::ostream& TestContext::tout(TraceLevel tl) const
37{
38    return _tout.stream(tl);
39}
40
41//////////////////////////////////////////////////////////////////////////////
42
43
44TestContext::TraceStream::TraceStream(std::ostream& o, TraceLevel tl):
45    _traceLevel(tl),
46    _outputStreamPtr(&o),
47#if defined(WIN32) && !(defined(__CYGWIN__) || defined(__MINGW32__))
48    _nullStream("nul")
49#else
50    _nullStream("/dev/null")
51#endif
52{
53}
54
55TestContext::TraceStream::~TraceStream()
56{
57    _nullStream.close();
58}
59
60void TestContext::TraceStream::setTraceLevel(TraceLevel tl)
61{
62    _traceLevel = tl;
63}
64
65TestContext::TraceLevel TestContext::TraceStream::getTraceLevel() const
66{
67    return _traceLevel;
68}
69
70std::ostream& TestContext::TraceStream::stream(TestContext::TraceLevel tl)
71{
72    if(_traceLevel >= tl){
73        return *_outputStreamPtr;
74    }
75    return _nullStream;
76}
77
78//////////////////////////////////////////////////////////////////////////////
79
80TestGraph& TestGraph::instance()
81{
82    static TestGraph instance_;
83    return instance_;
84}
85
86TestSuite* TestGraph::root()
87{
88    return root_.get();
89}
90
91TestSuite* TestGraph::suite(const std::string& path, TestSuite* tsuite, bool createIfNecessary)
92{
93    using namespace std;
94
95    list<string> pathComponents;
96
97    std::string::const_iterator it1 = path.begin();
98    std::string::const_iterator it2 = it1;
99
100    // Dissect the path into it's constituent components
101    do{
102
103        while( it2 != path.end() && *it2 != '.' ) ++it2;
104
105        // Consider a check for "" empty strings?
106        pathComponents.push_back( std::string(it1,it2) );
107
108        if( it2 != path.end()) ++it2;
109
110        it1 = it2;
111
112    }while( it2 != path.end());
113
114    return suite(pathComponents.begin(), pathComponents.end(),
115            tsuite, createIfNecessary);
116
117}
118
119TestSuite* TestGraph::suite(
120        std::list<std::string>::iterator it,
121        std::list<std::string>::iterator end,
122        TestSuite* tsuite, bool createIfNecessary)
123{
124    using namespace std;
125
126    if( ! tsuite) tsuite = root();
127
128    // Make sure these tie up
129    if(*it != tsuite->name()) return 0;
130
131    ++it;
132    if(it == end) return tsuite;
133
134    Test* child = tsuite->findChild(*it);
135
136    if(child){
137
138        // We've found a child with the right name. But is it a
139        // test suite?
140
141        if(TestSuite* childSuite = dynamic_cast<TestSuite*>(child)){
142            return suite(it, end, childSuite, createIfNecessary);
143        }
144
145        // We could return 0 here, to indicate that someone is
146        // trying to add a TestSuite named 'xxx' to a suite with a
147        // Test already named 'xxx'. But we don't enforce uniqueness
148        // the other way round, so we don't do it this way round
149        // either. Carry on as normal, and create a TestSuite of
150        // the same name if createIfNecessary is true.
151
152    }
153
154    if(createIfNecessary){
155
156        TestSuite* childSuite = new TestSuite(*it);
157        tsuite->add(childSuite);
158        return suite(it, end, childSuite, createIfNecessary);
159    }
160
161    return 0;
162}
163
164TestGraph::TestGraph(): root_(new TestSuite("root"))
165{
166}
167
168
169//////////////////////////////////////////////////////////////////////////////
170
171bool TestQualifier::visitEnter( TestSuite* pSuite )
172{
173    _path.append( pSuite->name() );
174    _path += SEPCHAR;
175    return true;
176}
177
178// Leaving a composite: Pop its name from the Path
179bool TestQualifier::visitLeave( TestSuite* pSuite )
180{
181//    assert( _path.rfind( pSuite->name() + static_cast<const char>(SEPCHAR))
182//                == _path.size() - pSuite->name().size()  - 1);
183
184    _path.erase( _path.size() - pSuite->name().size() -1 );
185    return true;
186}
187
188// Provide read-only access to the current qualifier
189const std::string& TestQualifier::currentPath() const
190{
191    return _path;
192}
193
194//////////////////////////////////////////////////////////////////////////////
195
196osg::Timer TestRecord::timer_;
197
198void TestRecord::start()
199{
200    start_ = timer_.tick();
201}
202
203void TestRecord::stop()
204{
205    stop_ = timer_.tick();
206}
207
208void TestRecord::log(const TestFailureX& e)
209{
210    stop();
211    result_ = Failure;
212    problem_ = e.what();
213}
214
215void TestRecord::log(const TestErrorX& e)
216{
217    stop();
218    result_ = Error;
219    problem_ = e.what();
220}
221
222void TestRecord::log(const std::exception& e)
223{
224    stop();
225    result_ = Error;
226    problem_ = e.what();
227}
228
229void TestRecord::log(const std::string& s)
230{
231    stop();
232    result_ = Error;
233    problem_ = s;
234}
235
236TestRecord::TestRecord(const std::string& name):
237    name_(name),
238    start_(0),
239    stop_(0),
240    result_(Success),
241    problem_("No problem")
242{
243}
244
245std::ostream& operator<<(std::ostream& o,const TestRecord& tr)
246{
247    if(tr.result_ == TestRecord::Success)         o<<"pass";
248    else if(tr.result_ == TestRecord::Failure)    o<<"fail";
249    else                                          o<<"error";
250
251    o<<"\t"<<tr.name_;
252
253
254    //o<<tr.start_<<'\t'<<tr.stop_<<'\t'<<TestRecord::timer_.delta_s(tr.start_,tr.stop_);
255
256    // Just print out the duration
257    o<<'\t'<<TestRecord::timer_.delta_s(tr.start_,tr.stop_)<<'s';
258
259    if(tr.result_ != TestRecord::Success){
260        o<<'\t'<<tr.problem_;
261    }
262
263    return o;
264}
265
266//////////////////////////////////////////////////////////////////////////////
267
268TestRunner::TestRunner( TestContext& ctx ) : _ctx( ctx )
269{
270}
271
272void TestRunner::specify( const std::string& sQualifiedName )
273{
274    _tests.push_back( sQualifiedName );
275}
276
277bool TestRunner::visitEnter( TestSuite* pSuite )
278{
279    TestQualifier::visitEnter( pSuite );
280    return !_ctx.shouldStop();
281}
282
283#ifndef DOXYGEN_SHOULD_SKIP_THIS
284
285namespace osgUtx{
286
287struct isSpecified{
288
289    const std::string& pTestName_;
290
291    isSpecified(const std::string& s): pTestName_(s) {}
292
293    bool operator()(const std::string& specifiedTest){
294        return pTestName_.find(specifiedTest) == 0;
295    }
296};
297
298}
299
300#endif /* DOXYGEN_SHOULD_SKIP_THIS */
301
302bool TestRunner::visit( TestCase* pTest )
303{
304    if ( std::find_if(_tests.begin(),_tests.end(),
305                      osgUtx::isSpecified(currentPath() + pTest->name() ) ) != _tests.end()) perform( pTest );
306
307    return !_ctx.shouldStop();
308}
309
310bool TestRunner::visitLeave( TestSuite* pSuite )
311{
312    TestQualifier::visitLeave( pSuite );
313    return !_ctx.shouldStop();
314}
315
316void TestRunner::perform( TestCase* pTest )
317{
318    TestRecord& record = _db.createRecord( currentPath() + pTest->name() );
319
320    try
321    {
322        record.start();
323        pTest->run( _ctx );
324        record.stop();
325    }
326
327    catch ( const TestFailureX& e )
328    {
329        record.log( e );
330    }
331    catch ( const TestErrorX& e )
332    {
333        record.log( e );
334    }
335    catch ( const std::exception& e )
336    {
337        record.log( e );
338    }
339    catch ( ... )
340    {
341        record.log( std::string("Unknown") );
342    }
343
344
345    _ctx.tout(TestContext::Results) << record << std::endl;
346}
347
348//////////////////////////////////////////////////////////////////////////////
349
350TestSuite::TestSuite( const std::string& name ) : Test( name )
351{
352}
353
354void TestSuite::add( Test* pTest )
355{
356    _tests.push_back( pTest );
357}
358
359Test* TestSuite::findChild(const std::string& name)
360{
361    for(Tests::iterator it = _tests.begin();
362        it != _tests.end();
363        ++it){
364
365        if ((*it)->name() == name) return (*it).get();
366    }
367
368    return 0;
369}
370
371bool TestSuite::accept( Test::Visitor& v )
372{
373    if ( v.visitEnter( this ) )
374    {
375        Tests::iterator end = _tests.end();
376        for ( Tests::iterator at = _tests.begin(); at != end; ++at )
377            if ( !(*at)->accept( v ) )
378                break;
379    }
380
381    return v.visitLeave( this );   // continue with siblings?
382}
383
384//////////////////////////////////////////////////////////////////////////////
385
386bool QualifiedTestPrinter::visit( TestCase* pTest )
387{
388    osg::notify(osg::NOTICE) << currentPath() + pTest->name() << std::endl;
389    return true;
390}
391
392//////////////////////////////////////////////////////////////////////////////
393
394
395}
Note: See TracBrowser for help on using the browser.