• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  (C) Copyright Gennadiy Rozental 2001-2014.
2 //  (C) Copyright Gennadiy Rozental & Ullrich Koethe 2001.
3 //  Distributed under the Boost Software License, Version 1.0.
4 //  (See accompanying file LICENSE_1_0.txt or copy at
5 //  http://www.boost.org/LICENSE_1_0.txt)
6 
7 //  See http://www.boost.org/libs/test for the library home page.
8 
9 // Boost.Test
10 #include <boost/test/tools/floating_point_comparison.hpp>
11 #include <boost/test/unit_test.hpp>
12 using namespace boost::unit_test;
13 using boost::math::fpc::close_at_tolerance;
14 using boost::math::fpc::percent_tolerance;
15 
16 // BOOST
17 #include <boost/lexical_cast.hpp>
18 
19 // STL
20 #include <functional>
21 #include <iostream>
22 #include <iomanip>
23 #include <memory>
24 #include <stdexcept>
25 
26 //____________________________________________________________________________//
27 
28 struct account {
accountaccount29     account()
30     : m_amount(0.0)
31     {}
32 
depositaccount33     void deposit(double amount) { m_amount += amount; }
withdrawaccount34     void withdraw(double amount)
35     {
36         if(amount > m_amount)
37         {
38             throw std::logic_error("You don't have that much money!");
39         }
40         m_amount -= amount;
41     }
balanceaccount42     double balance() const { return m_amount; }
43 
44 private:
45     double m_amount;
46 };
47 
48 //____________________________________________________________________________//
49 
50 struct account_test {
account_testaccount_test51     account_test( double init_value ) { m_account.deposit( init_value ); }
52 
53     account m_account;  // a very simple fixture
54 
test_initaccount_test55     void test_init()
56     {
57         // different kinds of non-critical tests
58         // they report the error and continue
59 
60         // standard assertion
61         // reports 'error in "account_test::test_init": test m_account.balance() >= 0.0 failed' on error
62         BOOST_CHECK( m_account.balance() >= 0.0 );
63 
64         // customized assertion
65         // reports 'error in "account_test::test_init": Initial balance should be more then 1, was actual_value' on error
66         BOOST_CHECK_MESSAGE( m_account.balance() > 1.0,
67                              "Initial balance should be more then 1, was " << m_account.balance() );
68 
69         // equality assertion (not very wise idea use equality check on floating point values)
70         // reports 'error in "account_test::test_init": test m_account.balance() == 5.0 failed [actual_value != 5]' on error
71         BOOST_CHECK_EQUAL( m_account.balance(), 5.0 );
72 
73         // closeness assertion for floating-point numbers (symbol (==) used to mark closeness, (!=) to mark non closeness )
74         // reports 'error in "account_test::test_init": test m_account.balance() (==) 10.0 failed [actual_value (!=) 10 (1e-010)]' on error
75         BOOST_CHECK_CLOSE( m_account.balance(), 10.0, /* tolerance */ 1e-10 );
76     }
77 
test_depositaccount_test78     void test_deposit()
79     {
80         // these 2 statements just to show that usage manipulators doesn't hurt Boost.Test output
81         std::cout << "Current balance: " << std::hex << (int)m_account.balance() << std::endl;
82         std::cerr << "Current balance: " << std::hex << (int)m_account.balance() << std::endl;
83 
84         float curr_ballance = (float)m_account.balance();
85         float deposit_value;
86 
87         std::cout << "Enter deposit value:\n";
88         std::cin  >> deposit_value;
89 
90         m_account.deposit( deposit_value );
91 
92         // correct result validation; could fail due to rounding errors; use BOOST_CHECK_CLOSE instead
93         // reports "test m_account.balance() == curr_ballance + deposit_value failed" on error
94         BOOST_CHECK( m_account.balance() == curr_ballance + deposit_value );
95 
96         // different kinds of critical tests
97 
98         // reports 'fatal error in "account_test::test_deposit": test m_account.balance() >= 100.0 failed' on error
99         BOOST_REQUIRE( m_account.balance() >= 100.0 );
100 
101         // reports 'fatal error in "account_test::test_deposit": Balance should be more than 500.1, was actual_value' on error
102         BOOST_REQUIRE_MESSAGE( m_account.balance() > 500.1,
103                                "Balance should be more than 500.1, was " << m_account.balance());
104 
105         // reports 'fatal error in "account_test::test_deposit": test std::not_equal_to<double>()(m_account.balance(), 999.9) failed
106         //          for (999.9, 999.9)' on error
107         BOOST_REQUIRE_PREDICATE( std::not_equal_to<double>(), (m_account.balance())(999.9) );
108 
109         // reports 'fatal error in "account_test::test_deposit": test close_at_tolerance<double>( 1e-9 )( m_account.balance(), 605.5)
110         //          failed for (actual_value, 605.5)
111         BOOST_REQUIRE_PREDICATE( close_at_tolerance<double>( percent_tolerance( 1e-9 ) ),
112                                  (m_account.balance())(605.5) );
113     }
114 
test_withdrawaccount_test115     void test_withdraw()
116     {
117         float curr_ballance = (float)m_account.balance();
118 
119         m_account.withdraw(2.5);
120 
121         // correct result validation; could fail due to rounding errors; use BOOST_CHECK_CLOSE instead
122         // reports "test m_account.balance() == curr_ballance - 2.5 failed" on error
123         BOOST_CHECK( m_account.balance() == curr_ballance - 2.5 );
124 
125         // reports 'error in "account_test::test_withdraw": exception std::runtime_error is expected' on error
126         BOOST_CHECK_THROW( m_account.withdraw( m_account.balance() + 1 ), std::runtime_error );
127 
128     }
129 };
130 
131 //____________________________________________________________________________//
132 
133 struct account_test_suite : public test_suite {
account_test_suiteaccount_test_suite134     account_test_suite( double init_value ) : test_suite("account_test_suite") {
135         // add member function test cases to a test suite
136         boost::shared_ptr<account_test> instance( new account_test( init_value ) );
137 
138         test_case* init_test_case     = BOOST_CLASS_TEST_CASE( &account_test::test_init, instance );
139         test_case* deposit_test_case  = BOOST_CLASS_TEST_CASE( &account_test::test_deposit, instance );
140         test_case* withdraw_test_case = BOOST_CLASS_TEST_CASE( &account_test::test_withdraw, instance );
141 
142         deposit_test_case->depends_on( init_test_case );
143         withdraw_test_case->depends_on( deposit_test_case );
144 
145         add( init_test_case, 1 );
146         add( deposit_test_case, 1 );
147         add( withdraw_test_case );
148     }
149 };
150 
151 //____________________________________________________________________________//
152 
153 test_suite*
init_unit_test_suite(int argc,char * argv[])154 init_unit_test_suite( int argc, char * argv[] ) {
155     framework::master_test_suite().p_name.value = "Unit test example 10";
156 
157     try {
158         if( argc < 2 )
159             throw std::logic_error( "Initial deposit expected" );
160 
161         framework::master_test_suite().add( new account_test_suite( boost::lexical_cast<double>( argv[1] ) ) );
162     }
163     catch( boost::bad_lexical_cast const& ) {
164          throw std::logic_error( "Initial deposit value should match format of double" );
165     }
166 
167     return 0;
168 }
169 
170 //____________________________________________________________________________//
171 
172 // EOF
173