• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  (C) Copyright Gennadiy Rozental 2001-2014.
2 //  Distributed under the Boost Software License, Version 1.0.
3 //  (See accompanying file LICENSE_1_0.txt or copy at
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 // Boost.Test
9 #include <boost/test/unit_test.hpp>
10 #include <boost/test/utils/algorithm.hpp>
11 #include <boost/test/tools/floating_point_comparison.hpp>
12 #include <boost/test/parameterized_test.hpp>
13 using namespace boost::unit_test;
14 
15 // BOOST
16 #include <boost/functional.hpp>
17 #include <boost/static_assert.hpp>
18 #include <boost/mem_fn.hpp>
19 #include <boost/bind/bind.hpp>
20 
21 // STL
22 #include <string>
23 #include <stdexcept>
24 #include <algorithm>
25 #include <functional>
26 #include <iostream>
27 #include <memory>
28 #include <list>
29 
30 //____________________________________________________________________________//
31 
32 template<int n>
33 struct power_of_10 {
34     BOOST_STATIC_CONSTANT( unsigned long, value = 10*power_of_10<n-1>::value );
35 };
36 
37 template<>
38 struct power_of_10<0> {
39     BOOST_STATIC_CONSTANT( unsigned long, value = 1 );
40 };
41 
42 //____________________________________________________________________________//
43 
44 template<int AlphabetSize>
45 class hash_function {
46 public:
47     BOOST_STATIC_ASSERT( AlphabetSize <= 5 );
48 
hash_function(std::string const & alphabet)49     explicit        hash_function( std::string const& alphabet )
50     : m_alphabet( alphabet )
51     {
52         if( m_alphabet.size() != AlphabetSize )
53             throw std::runtime_error( "Wrong alphabet size" );
54 
55         std::sort( m_alphabet.begin(), m_alphabet.end() );
56 
57         if( std::adjacent_find( m_alphabet.begin(), m_alphabet.end() ) != m_alphabet.end() )
58             throw std::logic_error( "Duplicate characters in alphabet" );
59     }
60 
operator ()(std::string const & arg)61     unsigned long   operator()( std::string const& arg )
62     {
63         m_result = 0;
64 
65         if( arg.length() > 8 )
66             throw std::runtime_error( "Wrong argument size" );
67 
68         std::string::const_iterator it = std::find_if( arg.begin(), arg.end(),
69             BOOST_TEST_BIND1ST( boost::mem_fun( &hash_function::helper_ ), this ) );
70 
71         if( it != arg.end() )
72             throw std::out_of_range( std::string( "Invalid character " ) + *it );
73 
74         return m_result;
75     }
76 
77 private:
helper_(char c)78     bool            helper_( char c )
79     {
80         std::string::const_iterator it = std::find( m_alphabet.begin(), m_alphabet.end(), c );
81 
82         if( it == m_alphabet.end() )
83             return true;
84 
85         m_result += power_of_10_( it - m_alphabet.begin() );
86 
87         return false;
88     }
89 
power_of_10_(int i)90     unsigned long   power_of_10_( int i ) {
91         switch( i ) {
92         case 0: return power_of_10<0>::value;
93         case 1: return power_of_10<1>::value;
94         case 2: return power_of_10<2>::value;
95         case 3: return power_of_10<3>::value;
96         case 4: return power_of_10<4>::value;
97         default: return 0;
98         }
99     }
100 
101     // Data members
102     std::string     m_alphabet;
103     unsigned long   m_result;
104 };
105 
106 //____________________________________________________________________________//
107 
108 struct hash_function_test_data {
109     std::string     orig_string;
110     unsigned long   exp_value;
111 
operator >>(std::istream & istr,hash_function_test_data & test_data)112     friend std::istream& operator>>( std::istream& istr, hash_function_test_data& test_data )
113     {
114         std::istream& tmp = istr >> test_data.orig_string;
115         return  !tmp ? tmp : istr >> test_data.exp_value;
116     }
117 };
118 
119 //____________________________________________________________________________//
120 
121 class hash_function_tester {
122 public:
hash_function_tester(std::string const & alphabet)123     explicit        hash_function_tester( std::string const& alphabet )
124     : m_function_under_test( alphabet ) {}
125 
test(hash_function_test_data const & test_data)126     void            test( hash_function_test_data const& test_data )
127     {
128         if( test_data.exp_value == (unsigned long)-1 )
129             BOOST_CHECK_THROW( m_function_under_test( test_data.orig_string ), std::runtime_error );
130         else if( test_data.exp_value == (unsigned long)-2 )
131             BOOST_CHECK_THROW( m_function_under_test( test_data.orig_string ), std::out_of_range );
132         else {
133             BOOST_TEST_MESSAGE( "Testing: " << test_data.orig_string );
134             BOOST_CHECK_EQUAL( m_function_under_test( test_data.orig_string ), test_data.exp_value );
135         }
136     }
137 
138 private:
139     hash_function<4> m_function_under_test;
140 };
141 
142 //____________________________________________________________________________//
143 
144 struct massive_hash_function_test : test_suite {
massive_hash_function_testmassive_hash_function_test145     massive_hash_function_test() : test_suite( "massive_hash_function_test" ) {
146         std::string alphabet;
147         std::cout << "Enter alphabet (4 characters without delimeters)\n";
148         std::cin >> alphabet;
149 
150         boost::shared_ptr<hash_function_tester> instance( new hash_function_tester( alphabet ) );
151 
152         std::cout << "\nEnter test data in a format [string] [value] to check correct calculation\n";
153         std::cout << "Enter test data in a format [string] -1 to check long string validation\n";
154         std::cout << "Enter test data in a format [string] -2 to check invalid argument string validation\n";
155 
156         std::list<hash_function_test_data> test_data_store;
157 
158         while( !std::cin.eof() ) {
159             hash_function_test_data test_data;
160 
161             if( !(std::cin >> test_data) )
162                 break;
163 
164             test_data_store.push_back( test_data );
165         }
166 
167         add( make_test_case( &hash_function_tester::test,
168                              "hash_function_tester",
169                              __FILE__,
170                              __LINE__,
171                              instance,
172                              test_data_store.begin(),
173                              test_data_store.end() ) );
174     }
175 };
176 
177 //____________________________________________________________________________//
178 
179 test_suite*
init_unit_test_suite(int,char * [])180 init_unit_test_suite( int, char* [] ) {
181     framework::master_test_suite().p_name.value = "Unit test example 12";
182 
183     framework::master_test_suite().add( new massive_hash_function_test );
184 
185     return 0;
186 }
187 
188 //____________________________________________________________________________//
189 
190 // EOF
191