1//  (C) Copyright Gennadiy Rozental 2005-2008.
2//  Use, modification, and distribution are subject to the
3//  Boost Software License, ELOG_VER 1.0. (See accompanying file
4//  http://www.boost.org/LICENSE_1_0.txt)
5
6//  See http://www.boost.org/libs/test for the library home page.
7//
8//  File        : $RCSfile$
9//
10//  Version     : $Revision: 54633 $
11//
12//  Description : Facilities to perform interaction based testng of logged expectations
13// ***************************************************************************
14
15#ifndef BOOST_TEST_LOGGED_EXPECTATIONS_IPP_120905GER
16#define BOOST_TEST_LOGGED_EXPECTATIONS_IPP_120905GER
17
18// Boost.Test
19#include <boost/test/detail/config.hpp>
20
21#if BOOST_TEST_SUPPORT_INTERACTION_TESTING
22
23#include <boost/test/detail/global_typedef.hpp>
24
25#include <boost/test/utils/callback.hpp>
26#include <boost/test/utils/iterator/token_iterator.hpp>
27
28#include <boost/test/interaction_based.hpp>
29#include <boost/test/test_tools.hpp>
30
31#include <boost/test/detail/suppress_warnings.hpp>
32
33// Boost
34#include <boost/lexical_cast.hpp>
35
36// STL
37#include <fstream>
38
39//____________________________________________________________________________//
40
41namespace boost {
42
43using namespace ::boost::unit_test;
44
45namespace itest {
46
47// ************************************************************************** //
48// **************    logged expectation test implementation    ************** //
49// ************************************************************************** //
50
51struct expectations_logger : itest::manager {
52    // Constructor
53    expectations_logger( const_string log_file_name, bool test_or_log );
54
55    virtual bool        decision_point( const_string, std::size_t );
56    virtual unsigned    enter_scope( const_string, std::size_t, const_string scope_name );
57    virtual void        allocated( const_string, std::size_t, void*, std::size_t s );
58    virtual void        data_flow( const_string d );
59    virtual std::string return_value( const_string default_value );
60
61private:
62    // Data members
63    bool            m_test_or_log;
64    std::fstream    m_log_file;
65};
66
67literal_string ELOG_VER     = "1.0";
68literal_string CLMN_SEP     = "|";
69static const char LINE_SEP  = '\n';
70
71literal_string FILE_SIG     = "ELOG";
72literal_string SCOPE_SIG    = "SCOPE";
73literal_string ALLOC_SIG    = "ALLOC";
74literal_string DP_SIG       = "SWITCH";
75literal_string DATA_SIG     = "DATA";
76literal_string RETURN_SIG   = "RETURN";
77
78//____________________________________________________________________________//
79
80expectations_logger::expectations_logger( const_string log_file_name, bool test_or_log )
81: m_test_or_log( test_or_log )
82{
83    BOOST_REQUIRE_MESSAGE( !log_file_name.is_empty(), "Empty expectations log file name" );
84
85    m_log_file.open( log_file_name.begin(), test_or_log ? std::ios::in : std::ios::out );
86
87    BOOST_REQUIRE_MESSAGE( m_log_file.is_open(),
88                           "Can't open expectations log file " << log_file_name
89                                << " for " << ( m_test_or_log ? "reading" : "writing") );
90
91    if( m_test_or_log ) {
92        std::string line;
93
94        std::getline( m_log_file, line, LINE_SEP );
95
96        const_string cline( line );
97        string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none));
98
99        BOOST_CHECK_EQUAL( *tit, FILE_SIG );
100        ++tit;
101        BOOST_CHECK_EQUAL( *tit, ELOG_VER );
102    }
103    else {
104        m_log_file << FILE_SIG << CLMN_SEP << ELOG_VER << LINE_SEP;
105    }
106}
107
108//____________________________________________________________________________//
109
110bool
111expectations_logger::decision_point( const_string, std::size_t )
112{
113    if( m_test_or_log ) {
114        std::string line;
115
116        std::getline( m_log_file, line, LINE_SEP );
117
118        const_string cline( line );
119        string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none));
120
121        BOOST_CHECK_EQUAL( *tit, DP_SIG ); ++tit;
122        return lexical_cast<bool>( *tit );
123    }
124    else {
125        m_log_file << DP_SIG << CLMN_SEP << std::boolalpha << true << LINE_SEP;
126
127        return true;
128    }
129}
130
131//____________________________________________________________________________//
132
133unsigned
134expectations_logger::enter_scope( const_string, std::size_t, const_string scope_name )
135{
136    if( m_test_or_log ) {
137        std::string line;
138
139        std::getline( m_log_file, line, LINE_SEP );
140
141        const_string cline( line );
142        string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none));
143
144        BOOST_CHECK_EQUAL( *tit, SCOPE_SIG ); ++tit;
145        BOOST_CHECK_EQUAL( *tit, scope_name );
146    }
147    else {
148        m_log_file << SCOPE_SIG << CLMN_SEP << scope_name << LINE_SEP;
149    }
150
151    return 0;
152}
153
154//____________________________________________________________________________//
155
156void
157expectations_logger::allocated( const_string, std::size_t, void*, std::size_t s )
158{
159    if( m_test_or_log ) {
160        std::string line;
161
162        std::getline( m_log_file, line, LINE_SEP );
163
164        const_string cline( line );
165        string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none));
166
167        BOOST_CHECK_EQUAL( *tit, ALLOC_SIG ); ++tit;
168        BOOST_CHECK_EQUAL( lexical_cast<std::size_t>( *tit ), s );
169    }
170    else {
171        m_log_file << ALLOC_SIG << CLMN_SEP << s << LINE_SEP;
172    }
173}
174
175//____________________________________________________________________________//
176
177void
178expectations_logger::data_flow( const_string d )
179{
180    if( m_test_or_log ) {
181        std::string line;
182
183        std::getline( m_log_file, line, LINE_SEP );
184
185        const_string cline( line );
186        string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none));
187
188        BOOST_CHECK_EQUAL( *tit, DATA_SIG ); ++tit;
189        BOOST_CHECK_EQUAL( *tit, d );
190    }
191    else {
192        m_log_file << DATA_SIG << CLMN_SEP << d << LINE_SEP;
193    }
194}
195
196//____________________________________________________________________________//
197
198std::string
199expectations_logger::return_value( const_string default_value )
200{
201    if( m_test_or_log ) {
202        std::string line;
203
204        std::getline( m_log_file, line, LINE_SEP );
205
206        const_string cline( line );
207        string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none));
208
209        BOOST_CHECK_EQUAL( *tit, RETURN_SIG ); ++tit;
210
211        return std::string( tit->begin(), tit->size() );
212    }
213    else {
214        m_log_file << RETURN_SIG << CLMN_SEP << default_value << LINE_SEP;
215
216        return std::string();
217    }
218}
219
220//____________________________________________________________________________//
221
222// ************************************************************************** //
223// **************           logged expectations test           ************** //
224// ************************************************************************** //
225
226void BOOST_TEST_DECL
227logged_expectations( callback0<> const& F, const_string log_file_name, bool test_or_log )
228{
229    expectations_logger el( log_file_name, test_or_log );
230
231    F();
232}
233
234//____________________________________________________________________________//
235
236}  // namespace itest
237
238} // namespace boost
239
240//____________________________________________________________________________//
241
242#include <boost/test/detail/enable_warnings.hpp>
243
244#endif // not ancient compiler
245
246#endif // BOOST_TEST_LOGGED_EXPECTATIONS_IPP_120905GER
247