| 1 | // (C) Copyright Gennadiy Rozental 2001-2005. |
|---|
| 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/floating_point_comparison.hpp> |
|---|
| 11 | #include <boost/test/unit_test.hpp> |
|---|
| 12 | using boost::unit_test::test_suite; |
|---|
| 13 | using boost::unit_test::test_case; |
|---|
| 14 | using boost::test_tools::close_at_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 | struct account { |
|---|
| 27 | account() |
|---|
| 28 | : m_amount(0.0) |
|---|
| 29 | {} |
|---|
| 30 | |
|---|
| 31 | void deposit(double amount) { m_amount += amount; } |
|---|
| 32 | void withdraw(double amount) |
|---|
| 33 | { |
|---|
| 34 | if(amount > m_amount) |
|---|
| 35 | { |
|---|
| 36 | throw std::logic_error("You don't have that much money!"); |
|---|
| 37 | } |
|---|
| 38 | m_amount -= amount; |
|---|
| 39 | } |
|---|
| 40 | double balance() const { return m_amount; } |
|---|
| 41 | |
|---|
| 42 | private: |
|---|
| 43 | double m_amount; |
|---|
| 44 | }; |
|---|
| 45 | |
|---|
| 46 | struct account_test { |
|---|
| 47 | account_test( double init_value ) { m_account.deposit( init_value ); } |
|---|
| 48 | |
|---|
| 49 | account m_account; // a very simple fixture |
|---|
| 50 | |
|---|
| 51 | void test_init() |
|---|
| 52 | { |
|---|
| 53 | // different kinds of non-critical tests |
|---|
| 54 | // they report the error and continue |
|---|
| 55 | |
|---|
| 56 | // standard assertion |
|---|
| 57 | // reports 'error in "account_test::test_init": test m_account.balance() >= 0.0 failed' on error |
|---|
| 58 | BOOST_CHECK( m_account.balance() >= 0.0 ); |
|---|
| 59 | |
|---|
| 60 | // customized assertion |
|---|
| 61 | // reports 'error in "account_test::test_init": Initial balance should be more then 1, was actual_value' on error |
|---|
| 62 | BOOST_CHECK_MESSAGE( m_account.balance() > 1.0, |
|---|
| 63 | "Initial balance should be more then 1, was " << m_account.balance() ); |
|---|
| 64 | |
|---|
| 65 | // equality assertion (not very wise idea use equlality check on floating point values) |
|---|
| 66 | // reports 'error in "account_test::test_init": test m_account.balance() == 5.0 failed [actual_value != 5]' on error |
|---|
| 67 | BOOST_CHECK_EQUAL( m_account.balance(), 5.0 ); |
|---|
| 68 | |
|---|
| 69 | // closeness assertion for floating-point numbers (symbol (==) used to mark closeness, (!=) to mark non closeness ) |
|---|
| 70 | // reports 'error in "account_test::test_init": test m_account.balance() (==) 10.0 failed [actual_value (!=) 10 (1e-010)]' on error |
|---|
| 71 | BOOST_CHECK_CLOSE( m_account.balance(), 10.0, /* tolerance */ 1e-10 ); |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | void test_deposit() |
|---|
| 75 | { |
|---|
| 76 | // these 2 statements just to show that usage manipulators doesn't hurt Boost.Test output |
|---|
| 77 | std::cout << "Current balance: " << std::hex << (int)m_account.balance() << std::endl; |
|---|
| 78 | std::cerr << "Current balance: " << std::hex << (int)m_account.balance() << std::endl; |
|---|
| 79 | |
|---|
| 80 | float curr_ballance = (float)m_account.balance(); |
|---|
| 81 | float deposit_value; |
|---|
| 82 | |
|---|
| 83 | std::cout << "Enter deposit value:\n"; |
|---|
| 84 | std::cin >> deposit_value; |
|---|
| 85 | |
|---|
| 86 | m_account.deposit( deposit_value ); |
|---|
| 87 | |
|---|
| 88 | // correct result validation; could fail due to rounding errors; use BOOST_CHECK_CLOSE instead |
|---|
| 89 | // reports "test m_account.balance() == curr_ballance + deposit_value failed" on error |
|---|
| 90 | BOOST_CHECK( m_account.balance() == curr_ballance + deposit_value ); |
|---|
| 91 | |
|---|
| 92 | // different kinds of critical tests |
|---|
| 93 | |
|---|
| 94 | // reports 'fatal error in "account_test::test_deposit": test m_account.balance() >= 100.0 failed' on error |
|---|
| 95 | BOOST_REQUIRE( m_account.balance() >= 100.0 ); |
|---|
| 96 | |
|---|
| 97 | // reports 'fatal error in "account_test::test_deposit": Balance should be more than 500.1, was actual_value' on error |
|---|
| 98 | BOOST_REQUIRE_MESSAGE( m_account.balance() > 500.1, |
|---|
| 99 | "Balance should be more than 500.1, was " << m_account.balance()); |
|---|
| 100 | |
|---|
| 101 | // reports 'fatal error in "account_test::test_deposit": test std::not_equal_to<double>()(m_account.balance(), 999.9) failed |
|---|
| 102 | // for (999.9, 999.9)' on error |
|---|
| 103 | BOOST_REQUIRE_PREDICATE( std::not_equal_to<double>(), (m_account.balance())(999.9) ); |
|---|
| 104 | |
|---|
| 105 | // reports 'fatal error in "account_test::test_deposit": test close_at_tolerance<double>( 1e-9 )( m_account.balance(), 605.5) |
|---|
| 106 | // failed for (actual_value, 605.5) |
|---|
| 107 | BOOST_REQUIRE_PREDICATE( close_at_tolerance<double>( 1e-9 ), (m_account.balance())(605.5) ); |
|---|
| 108 | } |
|---|
| 109 | |
|---|
| 110 | void test_withdraw() |
|---|
| 111 | { |
|---|
| 112 | float curr_ballance = (float)m_account.balance(); |
|---|
| 113 | |
|---|
| 114 | m_account.withdraw(2.5); |
|---|
| 115 | |
|---|
| 116 | // correct result validation; could fail due to rounding errors; use BOOST_CHECK_CLOSE instead |
|---|
| 117 | // reports "test m_account.balance() == curr_ballance - 2.5 failed" on error |
|---|
| 118 | BOOST_CHECK( m_account.balance() == curr_ballance - 2.5 ); |
|---|
| 119 | |
|---|
| 120 | // reports 'error in "account_test::test_withdraw": exception std::runtime_error is expected' on error |
|---|
| 121 | BOOST_CHECK_THROW( m_account.withdraw( m_account.balance() + 1 ), std::runtime_error ); |
|---|
| 122 | |
|---|
| 123 | } |
|---|
| 124 | }; |
|---|
| 125 | |
|---|
| 126 | struct account_test_suite : public test_suite { |
|---|
| 127 | account_test_suite( double init_value ) : test_suite("account_test_suite") { |
|---|
| 128 | // add member function test cases to a test suite |
|---|
| 129 | boost::shared_ptr<account_test> instance( new account_test( init_value ) ); |
|---|
| 130 | |
|---|
| 131 | test_case* init_test_case = BOOST_CLASS_TEST_CASE( &account_test::test_init, instance ); |
|---|
| 132 | test_case* deposit_test_case = BOOST_CLASS_TEST_CASE( &account_test::test_deposit, instance ); |
|---|
| 133 | test_case* withdraw_test_case = BOOST_CLASS_TEST_CASE( &account_test::test_withdraw, instance ); |
|---|
| 134 | |
|---|
| 135 | deposit_test_case->depends_on( init_test_case ); |
|---|
| 136 | withdraw_test_case->depends_on( deposit_test_case ); |
|---|
| 137 | |
|---|
| 138 | add( init_test_case, 1 ); |
|---|
| 139 | add( deposit_test_case, 1 ); |
|---|
| 140 | add( withdraw_test_case ); |
|---|
| 141 | } |
|---|
| 142 | }; |
|---|
| 143 | |
|---|
| 144 | test_suite* |
|---|
| 145 | init_unit_test_suite( int argc, char * argv[] ) { |
|---|
| 146 | test_suite* test = BOOST_TEST_SUITE( "Unit test example 3" ); |
|---|
| 147 | |
|---|
| 148 | try { |
|---|
| 149 | if( argc < 2 ) |
|---|
| 150 | return (test_suite*)0; |
|---|
| 151 | |
|---|
| 152 | test->add( new account_test_suite( boost::lexical_cast<double>( argv[1] ) ) ); |
|---|
| 153 | } |
|---|
| 154 | catch( boost::bad_lexical_cast& ) { |
|---|
| 155 | return (test_suite*)0; |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | return test; |
|---|
| 159 | } |
|---|
| 160 | |
|---|
| 161 | // EOF |
|---|