xdrpp
RFC4506 XDR compiler and message library
autocheck.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 
3 /** \file autocheck.h Support for using the [autocheck
4  * framework](https://github.com/thejohnfreeman/autocheck/wiki) with
5  * XDR data types. If you include this file (which requires the
6  * autocheck headers to be available), you can generate arbitrary
7  * instances of XDR types for testing your application. For example:
8  * \code
9  * // g will generate arbitrary values of type my_xdr_type
10  * autocheck::generator<my_xdr_type> g;
11  * // For variable size objects (vectors, strings, linked lists),
12  * // size indicates how big to make them. For numeric values,
13  * // size affects how big the number is likely to be.
14  * size_t size = 50;
15  * my_xdr_type arbitrary_value = g(object_size);
16  * fuzz_with(arbitrary_value);
17  * \endcode
18  */
19 
20 #ifndef _XDRC_AUTOCHECK_H_HEADER_INCLUDED_
21 #define _XDRC_AUTOCHECK_H_HEADER_INCLUDED_ 1
22 
23 #include <autocheck/autocheck.hpp>
24 #include <xdrpp/types.h>
25 
26 namespace xdr {
27 
28 #ifndef XDR_AUTOCHECK_FUZZY_STRINGS
29 // If defined to 0, changes the behavior of the library to generate
30 // strings with ASCII characters with small size parameters. The
31 // default (1) generates strings with arbitrary bytes.
32 #define XDR_AUTOCHECK_FUZZY_STRINGS 1
33 #endif // !XDR_AUTOCHECK_FUZZY_STRINGS
34 
35 namespace detail {
36 
37 //! Convert an int to a uint8_t or char, extracting the low byte.
38 //! This is harder than it sounds when char is signed, because
39 //! converting to a smaller signed type yields an
40 //! implementation-defined value. Worse, MSVC with certain options
41 //! goes even further and crashes the program when you simply cast an
42 //! int to a char. Since there's no equivalent of reinterpret_cast
43 //! between signed and unsigned values, and since even the standard
44 //! union trick may be unsafe according to:
45 //!
46 //! http://stackoverflow.com/questions/11373203/accessing-inactive-union-member-undefined
47 //!
48 //! we just gave up and did the brute force arithmetic thing, taking
49 //! advantage of the fact that all these one-byte values get promoted
50 //! to int for arithmetic.
51 template<typename T> constexpr T
52 to_int8(uint8_t u)
53 {
54  return u <= std::numeric_limits<T>::max() ? u :
55  u + (std::numeric_limits<T>::min() - std::numeric_limits<T>::max());
56 }
57 template<> constexpr uint8_t
58 to_int8<uint8_t>(uint8_t u)
59 {
60  return u;
61 }
62 
63 }
64 
65 struct generator_t {
66  std::size_t size_;
67  Constexpr explicit generator_t(std::size_t size) : size_(size) {}
68 
69  // Handle char and uint8_t (which can legally be the same type for
70  // some compilers), allowing variable_nelem cases to handle both
71  // containers and bytes (string/opaque).
72  template<typename T> typename
73  std::enable_if<(std::is_same<T, char>::value
74  || std::is_same<T, std::uint8_t>::value)>::type
75  operator()(T &t) const {
76 #if XDR_AUTOCHECK_FUZZY_STRINGS
77  t = detail::to_int8<T>(uint8_t(autocheck::generator<int>{}(0x10000)));
78 #else // !XDR_AUTOCHECK_FUZZY_STRINGS
79  t = detail::to_int8<T>(autocheck::generator<T>{}(size_));
80 #endif // !XDR_AUTOCHECK_FUZZY_STRINGS
81  }
82 
83  template<typename T> typename
84  std::enable_if<xdr_traits<T>::is_numeric>::type
85  operator()(T &t) const { t = autocheck::generator<T>{}(size_); }
86 
87  template<typename T> typename
88  std::enable_if<xdr_traits<T>::is_enum>::type
89  operator()(T &t) const {
90  t = xdr_traits<T>::from_uint(autocheck::generator<uint32_t>{}(size_));
91  }
92 
93  template<typename T> typename
94  std::enable_if<xdr_traits<T>::is_struct>::type
95  operator()(T &t) const { xdr_traits<T>::load(*this, t); }
96 
97  template<typename T> typename
98  std::enable_if<xdr_traits<T>::is_union>::type
99  operator()(T &t) const {
100  const auto &vals = T::_xdr_discriminant_values();
101  typename xdr_traits<T>::case_type v;
102  if (vals.empty())
103  v = autocheck::generator<decltype(v)>{}(size_);
104  else {
105  size_t n = autocheck::generator<size_t>{}(size_);
106  v = vals[n % vals.size()];
107  }
108  t._xdr_discriminant(v, false);
109  t._xdr_with_mem_ptr(field_archiver, v, *this, t, nullptr);
110  }
111 
112  // Shrunken size for elements of a container
113  inline size_t elt_size() const { return size_ >> 1; }
114 
115  template<typename T> typename
116  std::enable_if<xdr_traits<T>::variable_nelem == true>::type
117  operator()(T &t) const {
118  t.resize(autocheck::generator<std::uint32_t>{}(size_) % t.max_size());
119  generator_t g(elt_size());
120  for (auto &e : t)
121  archive(g, e);
122  }
123 
124  template<typename T> typename
125  std::enable_if<xdr_traits<T>::variable_nelem == false>::type
126  operator()(T &t) const {
127  generator_t g(elt_size());
128  for (auto &e : t)
129  archive(g, e);
130  }
131 
132  template<typename T> void
133  operator()(pointer<T> &t) const {
134  if (autocheck::generator<std::uint32_t>{}(size_)) {
135  generator_t g(elt_size());
136  archive(g, t.activate());
137  }
138  else
139  t.reset();
140  }
141 };
142 
143 } // namespace xdr
144 
145 namespace autocheck {
146 
147 template<typename T> class generator<
148  T, typename std::enable_if<xdr::xdr_traits<T>::valid
149  && !xdr::xdr_traits<T>::is_numeric>::type> {
150 public:
151  using result_type = T;
152  result_type operator()(size_t size) const {
153  xdr::generator_t g(size);
154  T t;
155  xdr::archive(g, t);
156  return t;
157  }
158 };
159 
160 } // namespace autocheck
161 
162 #endif // !_XDRC_AUTOCHECK_H_HEADER_INCLUDED_
Type definitions for xdrc compiler output.
Most of the xdrpp library is encapsulated in the xdr namespace.
Definition: arpc.cc:4
Optional data (represented with pointer notation in XDR source).
Definition: types.h:536
void archive(Archive &ar, T &&t, const char *name=nullptr)
By default, this function simply applies ar (which must be a function object) to t.
Definition: types.h:140
Metadata for all marshalable XDR types.
Definition: types.h:146
Constexpr const field_archiver_t field_archiver
Passed to _xdr_with_mem_ptr to archive the active union field.
Definition: types.h:888