source: trunk/test/Suite.h @ 2338

Last change on this file since 2338 was 2338, checked in by Peter, 11 years ago

adding an archetype class for distance concept and use that class in KNN and NCC. Adding CopyConstructible? to requirement for Distance concept

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.7 KB
Line 
1#ifndef _theplu_yat_test_suite_
2#define _theplu_yat_test_suite_
3
4// $Id: Suite.h 2338 2010-10-16 05:00:12Z peter $
5
6/*
7  Copyright (C) 2008 Jari Häkkinen, Peter Johansson
8  Copyright (C) 2009, 2010 Peter Johansson
9
10  This file is part of the yat library, http://dev.thep.lu.se/yat
11
12  The yat library is free software; you can redistribute it and/or
13  modify it under the terms of the GNU General Public License as
14  published by the Free Software Foundation; either version 3 of the
15  License, or (at your option) any later version.
16
17  The yat library is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  General Public License for more details.
21
22  You should have received a copy of the GNU General Public License
23  along with yat. If not, see <http://www.gnu.org/licenses/>.
24*/
25
26#include <boost/concept_archetype.hpp>
27
28#include <iosfwd>
29#include <sstream>
30
31namespace theplu {
32namespace yat {
33namespace test {
34
35  /**
36     \internal utility class for tests
37   */
38  class Suite
39  {
40  public:
41    Suite(int argc, char* argv[]);
42
43    /**
44     */
45    ~Suite(void);
46
47    /**
48       set ok to 'b && ok'
49
50       \return b
51    */
52    bool add(bool b);
53
54    /**
55       \return In verbose mode std::cerr, else a ofstream to "/dev/null".
56    */
57    std::ostream& err(void) const;
58
59    /**
60       \return true if \f$ |a-b| <= N * \epsilon * min(|a|,|b|) \f$
61       where \f$ \epsilon \f$ is std::numeric_limits<double>().epsilon()
62    */
63    bool equal(double a, double b, unsigned long int N=1);
64
65    /**
66       \return true if |\a a - \a b| <= \a margin
67    */
68    bool equal_fix(double a, double b, double margin=0);
69
70    /**
71       \return true if \f$ |a-b| <= N * sqrt(\epsilon) * min(|a|,|b|) \f$
72       where \f$ \epsilon \f$ is std::numeric_limits<double>().epsilon()
73    */
74    bool equal_sqrt(double a, double b, unsigned long int N=1);
75
76    /**
77       apply equal on ranges [first1, last1) and [first2, ...)
78    */
79    template<typename Iterator1, typename Iterator2>
80    bool equal_range(Iterator1 first1, Iterator1 last1, Iterator2 first2,
81                     unsigned int N=1);
82
83    /**
84       apply equal_fix on ranges [first1, last1) and [first2, ...)
85    */
86    template<typename Iterator1, typename Iterator2>
87    bool equal_range_fix(Iterator1 first1, Iterator1 last1, Iterator2 first2,
88                         double margin);
89
90    /**
91      \return true if test is ok
92    */
93    bool ok(void) const;
94
95    /**
96       \return In verbose mode std::cout, else a ofstream to "/dev/null".
97    */
98    std::ostream& out(void) const;
99   
100    /**
101       In verbose mode a final message is sent to std::cout.
102
103       If ok() is true: "Test is ok." otherwise
104       "Test failed."
105
106       \return 0 if ok.
107     */
108    int return_value(void) const;
109
110    template<typename TrivialIterator>
111    void test_trivial_iterator(const TrivialIterator&);
112   
113    template<typename InputIterator>
114    void test_input_iterator(InputIterator&);
115   
116    template<typename OutputIterator>
117    void test_output_iterator(OutputIterator&);
118 
119    template<typename ForwardIterator>
120    void test_forward_iterator(ForwardIterator);
121   
122    template<typename BidirectionalIterator>
123    void test_bidirectional_iterator(BidirectionalIterator);
124   
125    template<typename RandomAccessIterator>
126    void test_random_access_iterator(RandomAccessIterator);
127
128    template<typename Container2D>
129    void test_concept_container2d(const Container2D&);
130
131    template<typename MutableContainer2D>
132    void test_concept_mutable_container2d(MutableContainer2D&);
133
134    /**
135       Function writes to a stream using operator<<, creates a new
136       object using stream constructor, and the new object is written
137       to another stream, and function check if the two outputs are
138       equal.
139    */
140    template<class T>
141    bool test_stream(const T&) const;
142
143    /**
144       This function is similar to add(bool) and could be used to
145       detect/count known issues. When the issue is fixed, one can
146       replace the call to xadd(bool) with a call to add(bool).
147
148       If \a b is false a counter is incremented, which is used to in
149       return_value() to generate some printout on how many known
150       issues were detected.
151
152       If \a b is true, ok_ is set to false, becasue the known issue
153       is no longer an issue and one should replace the call with a
154       call to add(bool).
155     */
156    bool xadd(bool b);
157
158  private:
159    unsigned int known_issues_;
160    bool ok_;
161  };
162
163  /**
164     \return absolute path to file
165     \param local_path path relative to srcdir
166   */
167  std::string filename(const std::string& local_path);
168
169  /*
170    class to test (at compile time) that a function (or class) works
171    with a Container2D. Do not run any test using this class because
172    the class is not really functional at run time.
173
174    \see boost/concept_archetype.hpp
175   */
176  template<typename T>
177  class container2d_archetype
178  {
179  public:
180    typedef T value_type;
181    typedef const T& const_reference;
182    typedef const T* const_iterator; 
183    typedef const_iterator const_column_iterator;
184    typedef const_iterator const_row_iterator;
185    const_iterator begin(void) const { return &element_; }
186    const_column_iterator begin_column(size_t) const { return &element_; }
187    const_iterator begin_row(size_t) const { return &element_; }
188    const_iterator end(void) const { return NULL; }
189    const_column_iterator end_column(size_t) const { return NULL; }
190    const_iterator end_row(size_t) const { return NULL; }
191    size_t columns(void) const { return 0; }
192    size_t rows(void) const { return 0; }
193    const_reference operator()(size_t row, size_t column) const 
194    { return element_; }
195
196  protected:
197    T element_;
198  };
199
200  /*
201    class to test (at compile time) that a function (or class) works
202    with a MutableContainer2D. Do not run any test using this class because
203    the class is not really functional at run time.
204
205    \see boost/concept_archetype.hpp
206   */
207  template<typename T>
208  class mutable_container2d_archetype : public container2d_archetype<T>
209  {
210  public:
211    typedef T& reference;
212    typedef T* iterator; 
213    typedef iterator column_iterator;
214    typedef iterator row_iterator;
215    iterator begin(void) { return &this->element_; }
216    column_iterator begin_column(size_t) { return &this->element_; }
217    iterator begin_row(size_t) { return &this->element_; }
218    iterator end(void) { return NULL; }
219    column_iterator end_column(size_t) { return NULL; }
220    iterator end_row(size_t) { return NULL; }
221    reference operator()(size_t row, size_t column)
222    { return this->element_; }
223  };
224
225  /*
226    class to test (at compile time) that a function (or class) works
227    with a Distance. Do not run any test using this class because
228    the class is not really functional at run time.
229
230    \see boost/concept_archetype.hpp
231   */
232  class distance_archetype
233  {
234  public:
235    /// class must be constructible somehow, but we don't wanna assume
236    /// void constructor or any other common constructor so we use the
237    /// signature to allow construction without assuming too much.
238    distance_archetype(const boost::detail::dummy_constructor&) {};
239    distance_archetype(const distance_archetype&) {};
240    template<typename T1, typename T2>
241    double operator()(T1 first1, T1 last1, T2 first2) const { return 0.0; }
242  private:
243    distance_archetype(void);
244    distance_archetype& operator=(const distance_archetype&);
245  };
246
247  // template implementations
248
249  template<typename Iterator1, typename Iterator2>
250  bool Suite::equal_range(Iterator1 first1, Iterator1 last1, Iterator2 first2,
251                          unsigned int N)
252  {
253    while (first1!=last1){
254      if (!this->equal(*first1, *first2, N) )  {
255        return false;
256      }
257      ++first1;
258      ++first2;
259    }
260    return true;
261  }
262
263
264  template<typename Iterator1, typename Iterator2>
265  bool Suite::equal_range_fix(Iterator1 first1, Iterator1 last1, 
266                              Iterator2 first2, double margin)
267  {
268    while (first1!=last1){
269      if (!this->equal_fix(*first1, *first2, margin) )   {
270        return false;
271      }
272      ++first1;
273      ++first2;
274    }
275    return true;
276  }
277
278
279  // return true if we can write to a write-protected file
280  bool run_as_root(void);
281
282  template<class T>
283  bool Suite::test_stream(const T& t) const
284  {
285    this->err() << "Checking that output stream is valid as an input stream\n";
286    std::stringstream ss;
287    this->err() << "writing to output\n";
288    ss << t;
289    this->err() << "creating a new object from output\n";
290    T t2(ss);
291    std::stringstream ss2;
292    this->err() << "writing to output\n";
293    ss2 << t2;
294    bool ok = ss2.str()==ss.str();
295    if (!ok) {
296      this->err() << "ERROR: first object gave following output:\n" 
297                  << ss.str() << "\n"
298                  << "ERROR: and second object gave following output:\n" 
299                  << ss2.str() << "\n";
300    }
301    return ok;
302  }
303
304  template<typename TrivialIterator>
305  void Suite::test_trivial_iterator(const TrivialIterator& iter)
306  {
307    err() << "  testing Trivial features" << std::endl;
308    typename std::iterator_traits<TrivialIterator>::value_type tmp = *iter;
309    add(tmp==*iter);
310    TrivialIterator default_constructed;
311    default_constructed == default_constructed; // avoid compiler warning
312  }
313 
314  template<typename InputIterator>
315  void Suite::test_input_iterator(InputIterator& iter)
316  {
317    test_trivial_iterator(iter);
318    err() << "  testing Input features" << std::endl;
319    // just to check compilation
320    if (false) {
321      ++iter;
322      iter++;
323    }
324  }
325 
326  template<typename OutputIterator>
327  void Suite::test_output_iterator(OutputIterator& iter)
328  {
329    test_trivial_iterator(iter);
330    err() << "  testing Output features" << std::endl;
331  }
332 
333  template<typename ForwardIterator>
334  void Suite::test_forward_iterator(ForwardIterator iter)
335  {
336    test_output_iterator(iter);
337    test_input_iterator(iter);
338    err() << "  testing Forward features" << std::endl;
339   
340    typename std::iterator_traits<ForwardIterator>::value_type tmp = *iter;
341    // testing multiple traversing is possible and does not change the data
342    ForwardIterator iter1 = iter;
343    ++iter1;
344    add(iter!=iter1);
345    ForwardIterator iter2 = iter;
346    ++iter2;
347    add(tmp==*iter);
348  }
349 
350  template<typename BidirectionalIterator>
351  void Suite::test_bidirectional_iterator(BidirectionalIterator iter)
352  {
353    test_forward_iterator(iter);
354    bool ok_cached = ok();
355    err() << "  testing Bidirectional features" << std::endl;
356    const BidirectionalIterator i = iter;
357    BidirectionalIterator tmp = iter++;
358    if (!add(tmp==i)) {
359      err() << "iter++ does not return iter\n";
360    }
361    if (!add(++tmp==iter)) {
362      err() << "++iter failed\n";
363    }
364    if (!add(--tmp==i)) {
365      err() << "--iter failed\n";
366    }
367    tmp = iter--;
368    if (!add(--tmp==iter))
369      err() << "iter-- failed" << std::endl;
370    if (ok_cached && !ok())
371      err() << "failed" << std::endl;
372  }
373
374  template<typename RandomAccessIterator>
375  void Suite::test_random_access_iterator(RandomAccessIterator iter)
376  {
377    test_bidirectional_iterator(iter);
378    err() << "  testing RandomAccess features" << std::endl;
379    bool ok_cached = ok();
380    RandomAccessIterator iter2 = iter;
381    iter2 += 1;
382    iter2 -= 1;
383    RandomAccessIterator& iter3 = (iter2 += 1);
384    RandomAccessIterator& iter4 = (iter3 -= 1);
385    if (!add(iter2 == iter4))
386      err() << "operator-(int) failed" << std::endl;
387    add(++iter2 == iter3);
388   
389    RandomAccessIterator iter5 = iter + 0;
390    RandomAccessIterator iter6 = 0 + iter;
391    add(iter6 == iter5);
392   
393    RandomAccessIterator iter7 = iter - 0;
394    add(iter7 == iter);
395    add(iter7 - iter == 0);
396    add(! (iter7<iter));
397   
398    typename RandomAccessIterator::value_type tmp = iter[0];
399    typename RandomAccessIterator::value_type tmp2 = *iter;
400    tmp = tmp; // avoid compiler warning
401    if (!add(tmp == tmp2))
402      err() << "operator[] failed" << std::endl;
403    if (!add(iter[0] == *iter))
404      err() << "operator[] failed" << std::endl;
405    if (ok_cached && !ok())
406      err() << "failed" << std::endl;
407  }
408
409  template<typename Container2D>
410  void Suite::test_concept_container2d(const Container2D& c)
411  {
412    typedef typename Container2D::value_type value_type;
413    typedef typename Container2D::const_reference const_reference;
414    typedef typename Container2D::const_iterator const_iterator;
415    typedef typename Container2D::const_column_iterator const_column_iterator;
416    typedef typename Container2D::const_row_iterator const_row_iterator;
417    const_iterator ci = c.begin();
418    const_column_iterator cci = c.begin_column(0);
419    const_row_iterator cri = c.begin_row(0);
420    ci = c.end();
421    cci = c.end_column(0);
422    cri = c.end_row(0);
423    size_t cols = c.columns();
424    size_t rows = c.rows();
425    cols = rows; // just to avoid compiler warning
426    const_reference x = c(0,0);
427    value_type y;
428    y = x;
429  }
430
431  template<typename MutableContainer2D>
432  void Suite::test_concept_mutable_container2d(MutableContainer2D& mc)
433  {
434    test_concept_container2d(mc);
435    typedef typename MutableContainer2D::reference reference;
436    typedef typename MutableContainer2D::iterator iterator;
437    typedef typename MutableContainer2D::column_iterator column_iterator;
438    typedef typename MutableContainer2D::row_iterator row_iterator;
439    iterator i = mc.begin();
440    column_iterator ci = mc.begin_column(0);
441    row_iterator ri = mc.begin_row(0);
442    *i = *ci; 
443    *ci = *i; 
444    *ri = *i; 
445    i = mc.end();
446    ci = mc.end_column(0);
447    ri = mc.end_row(0);
448    reference x = mc(0,0);
449    x = *mc.begin();
450  }
451
452}}}
453
454#endif
Note: See TracBrowser for help on using the repository browser.