source: trunk/test/Suite.h @ 2649

Last change on this file since 2649 was 2649, checked in by Peter, 10 years ago

skeleton for class Kendall (refs #494).

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