unit_test_example_10.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. // See http://www.boost.org/libs/test for the library home page.
  7. // Boost.Test
  8. #include <boost/test/tools/floating_point_comparison.hpp>
  9. #include <boost/test/unit_test.hpp>
  10. using namespace boost::unit_test;
  11. using boost::math::fpc::close_at_tolerance;
  12. using boost::math::fpc::percent_tolerance;
  13. // BOOST
  14. #include <boost/lexical_cast.hpp>
  15. // STL
  16. #include <functional>
  17. #include <iostream>
  18. #include <iomanip>
  19. #include <memory>
  20. #include <stdexcept>
  21. //____________________________________________________________________________//
  22. struct account {
  23. account()
  24. : m_amount(0.0)
  25. {}
  26. void deposit(double amount) { m_amount += amount; }
  27. void withdraw(double amount)
  28. {
  29. if(amount > m_amount)
  30. {
  31. throw std::logic_error("You don't have that much money!");
  32. }
  33. m_amount -= amount;
  34. }
  35. double balance() const { return m_amount; }
  36. private:
  37. double m_amount;
  38. };
  39. //____________________________________________________________________________//
  40. struct account_test {
  41. account_test( double init_value ) { m_account.deposit( init_value ); }
  42. account m_account; // a very simple fixture
  43. void test_init()
  44. {
  45. // different kinds of non-critical tests
  46. // they report the error and continue
  47. // standard assertion
  48. // reports 'error in "account_test::test_init": test m_account.balance() >= 0.0 failed' on error
  49. BOOST_CHECK( m_account.balance() >= 0.0 );
  50. // customized assertion
  51. // reports 'error in "account_test::test_init": Initial balance should be more then 1, was actual_value' on error
  52. BOOST_CHECK_MESSAGE( m_account.balance() > 1.0,
  53. "Initial balance should be more then 1, was " << m_account.balance() );
  54. // equality assertion (not very wise idea use equality check on floating point values)
  55. // reports 'error in "account_test::test_init": test m_account.balance() == 5.0 failed [actual_value != 5]' on error
  56. BOOST_CHECK_EQUAL( m_account.balance(), 5.0 );
  57. // closeness assertion for floating-point numbers (symbol (==) used to mark closeness, (!=) to mark non closeness )
  58. // reports 'error in "account_test::test_init": test m_account.balance() (==) 10.0 failed [actual_value (!=) 10 (1e-010)]' on error
  59. BOOST_CHECK_CLOSE( m_account.balance(), 10.0, /* tolerance */ 1e-10 );
  60. }
  61. void test_deposit()
  62. {
  63. // these 2 statements just to show that usage manipulators doesn't hurt Boost.Test output
  64. std::cout << "Current balance: " << std::hex << (int)m_account.balance() << std::endl;
  65. std::cerr << "Current balance: " << std::hex << (int)m_account.balance() << std::endl;
  66. float curr_ballance = (float)m_account.balance();
  67. float deposit_value;
  68. std::cout << "Enter deposit value:\n";
  69. std::cin >> deposit_value;
  70. m_account.deposit( deposit_value );
  71. // correct result validation; could fail due to rounding errors; use BOOST_CHECK_CLOSE instead
  72. // reports "test m_account.balance() == curr_ballance + deposit_value failed" on error
  73. BOOST_CHECK( m_account.balance() == curr_ballance + deposit_value );
  74. // different kinds of critical tests
  75. // reports 'fatal error in "account_test::test_deposit": test m_account.balance() >= 100.0 failed' on error
  76. BOOST_REQUIRE( m_account.balance() >= 100.0 );
  77. // reports 'fatal error in "account_test::test_deposit": Balance should be more than 500.1, was actual_value' on error
  78. BOOST_REQUIRE_MESSAGE( m_account.balance() > 500.1,
  79. "Balance should be more than 500.1, was " << m_account.balance());
  80. // reports 'fatal error in "account_test::test_deposit": test std::not_equal_to<double>()(m_account.balance(), 999.9) failed
  81. // for (999.9, 999.9)' on error
  82. BOOST_REQUIRE_PREDICATE( std::not_equal_to<double>(), (m_account.balance())(999.9) );
  83. // reports 'fatal error in "account_test::test_deposit": test close_at_tolerance<double>( 1e-9 )( m_account.balance(), 605.5)
  84. // failed for (actual_value, 605.5)
  85. BOOST_REQUIRE_PREDICATE( close_at_tolerance<double>( percent_tolerance( 1e-9 ) ),
  86. (m_account.balance())(605.5) );
  87. }
  88. void test_withdraw()
  89. {
  90. float curr_ballance = (float)m_account.balance();
  91. m_account.withdraw(2.5);
  92. // correct result validation; could fail due to rounding errors; use BOOST_CHECK_CLOSE instead
  93. // reports "test m_account.balance() == curr_ballance - 2.5 failed" on error
  94. BOOST_CHECK( m_account.balance() == curr_ballance - 2.5 );
  95. // reports 'error in "account_test::test_withdraw": exception std::runtime_error is expected' on error
  96. BOOST_CHECK_THROW( m_account.withdraw( m_account.balance() + 1 ), std::runtime_error );
  97. }
  98. };
  99. //____________________________________________________________________________//
  100. struct account_test_suite : public test_suite {
  101. account_test_suite( double init_value ) : test_suite("account_test_suite") {
  102. // add member function test cases to a test suite
  103. boost::shared_ptr<account_test> instance( new account_test( init_value ) );
  104. test_case* init_test_case = BOOST_CLASS_TEST_CASE( &account_test::test_init, instance );
  105. test_case* deposit_test_case = BOOST_CLASS_TEST_CASE( &account_test::test_deposit, instance );
  106. test_case* withdraw_test_case = BOOST_CLASS_TEST_CASE( &account_test::test_withdraw, instance );
  107. deposit_test_case->depends_on( init_test_case );
  108. withdraw_test_case->depends_on( deposit_test_case );
  109. add( init_test_case, 1 );
  110. add( deposit_test_case, 1 );
  111. add( withdraw_test_case );
  112. }
  113. };
  114. //____________________________________________________________________________//
  115. test_suite*
  116. init_unit_test_suite( int argc, char * argv[] ) {
  117. framework::master_test_suite().p_name.value = "Unit test example 10";
  118. try {
  119. if( argc < 2 )
  120. throw std::logic_error( "Initial deposit expected" );
  121. framework::master_test_suite().add( new account_test_suite( boost::lexical_cast<double>( argv[1] ) ) );
  122. }
  123. catch( boost::bad_lexical_cast const& ) {
  124. throw std::logic_error( "Initial deposit value should match format of double" );
  125. }
  126. return 0;
  127. }
  128. //____________________________________________________________________________//
  129. // EOF