Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
#include "dxxsconf.h"
2
#include "compiler-poison.h"
3
 
4
/* If DXX_HAVE_POISON_UNDEFINED is not zero,
5
 * array_managed_type::array_managed_type() is declared and must be
6
 * defined out of line.  These tests do not need to run any code at
7
 * array construction time, so force DXX_HAVE_POISON_UNDEFINED to be zero.
8
 */
9
#undef DXX_HAVE_POISON_UNDEFINED
10
#define DXX_HAVE_POISON_UNDEFINED       0
11
#include "valptridx.h"
12
#include "valptridx.tcc"
13
 
14
#define BOOST_TEST_DYN_LINK
15
#define BOOST_TEST_MODULE Rebirth valptridx
16
#include <boost/test/unit_test.hpp>
17
 
18
/* Convenience macro to prevent the compiler optimizer from performing
19
 * constant propagation of the input.  This ensures that build-time
20
 * tests are suppressed, allowing the runtime test to be emitted and
21
 * executed.
22
 */
23
#define OPTIMIZER_HIDE_VARIABLE(V)      asm("" : "=rm" (V) : "0" (V) : "memory")
24
 
25
/* Convenience function to pass an anonymous value (such as an integer
26
 * constant) through OPTIMIZER_HIDE_VARIABLE, then return it.  This is
27
 * needed for contexts where a bare asm() statement would not be legal.
28
 *
29
 * It also has the useful secondary effect of casting the input to a
30
 * type, if the caller explicitly sets the typename T.
31
 */
32
template <typename T>
33
static inline T optimizer_hidden_variable(T v)
34
{
35
        OPTIMIZER_HIDE_VARIABLE(v);
36
        return v;
37
}
38
 
39
/* Convenience macro to ignore the result of an expression in a way that
40
 * __attribute__((warn_unused_result)) does not warn that the result was
41
 * ignored.
42
 */
43
#define DXX_TEST_VALPTRIDX_IGNORE_RETURN(EXPR)  ({      auto &&r = EXPR; static_cast<void>(r); })
44
 
45
struct object
46
{
47
        /* No state needed - this module is testing valptridx, not the type
48
         * managed by valptridx.
49
         */
50
};
51
 
52
using objnum_t = uint16_t;
53
constexpr std::integral_constant<std::size_t, 350> MAX_OBJECTS{};
54
DXX_VALPTRIDX_DECLARE_SUBTYPE(, object, objnum_t, MAX_OBJECTS);
55
DXX_VALPTRIDX_DEFINE_SUBTYPE_TYPEDEFS(object, obj);
56
DXX_VALPTRIDX_DEFINE_GLOBAL_FACTORIES(object, obj, Objects);
57
 
58
valptridx<object>::array_managed_type Objects;
59
 
60
/* Some valptridx names are normally protected.  The tests need access
61
 * to them.  Define a subclass that relaxes the permissions.
62
 */
63
struct valptridx_access_override : valptridx<object>
64
{
65
        using base_type = valptridx<object>;
66
        using typename base_type::allow_end_construction;
67
        using typename base_type::index_range_exception;
68
        using typename base_type::null_pointer_exception;
69
        using typename base_type::report_error_uses_exception;
70
};
71
 
72
/* Test that using the factory does not throw an exception on the
73
 * highest valid index.
74
 */
75
BOOST_AUTO_TEST_CASE(idx_no_exception_near_end)
76
{
77
        BOOST_CHECK_NO_THROW(
78
                DXX_TEST_VALPTRIDX_IGNORE_RETURN(
79
                        Objects.vmptr(optimizer_hidden_variable<objnum_t>(MAX_OBJECTS - 1)))
80
                );
81
}
82
 
83
/* Test that using the factory does throw an exception on the lowest
84
 * invalid index and on the highest representable integer.
85
 */
86
BOOST_AUTO_TEST_CASE(idx_exception_at_end)
87
{
88
        if (!valptridx_access_override::report_error_uses_exception::value)
89
                /* If valptridx is configured not to use exceptions to report
90
                 * errors, these tests will fail even when the logic is correct.
91
                 * Skip them in that case.
92
                 */
93
                return;
94
        BOOST_CHECK_THROW(
95
                DXX_TEST_VALPTRIDX_IGNORE_RETURN(
96
                        Objects.vmptr(
97
                                optimizer_hidden_variable<objnum_t>(MAX_OBJECTS))),
98
                valptridx_access_override::index_range_exception);
99
 
100
        BOOST_CHECK_THROW(
101
                DXX_TEST_VALPTRIDX_IGNORE_RETURN(
102
                        Objects.vmptr(
103
                                optimizer_hidden_variable<objnum_t>(UINT16_MAX))),
104
                valptridx_access_override::index_range_exception);
105
}
106
 
107
BOOST_AUTO_TEST_CASE(iter_no_exception_at_allowed_end)
108
{
109
        /* Test the allowed side of end() handling for off-by-one bugs.
110
         */
111
        BOOST_CHECK_NO_THROW(DXX_TEST_VALPTRIDX_IGNORE_RETURN(
112
                        (Objects.set_count(optimizer_hidden_variable<objnum_t>(MAX_OBJECTS - 1)), Objects.vmptr.end())
113
        ));
114
 
115
        BOOST_CHECK_NO_THROW(DXX_TEST_VALPTRIDX_IGNORE_RETURN(
116
                        (Objects.set_count(optimizer_hidden_variable<objnum_t>(MAX_OBJECTS)), Objects.vmptr.end())
117
        ));
118
}
119
 
120
BOOST_AUTO_TEST_CASE(iter_exception_if_beyond_end)
121
{
122
        /* Test that end() throws an exception if the range's count exceeds
123
         * the valid storage size.
124
         */
125
        if (!valptridx_access_override::report_error_uses_exception::value)
126
                return;
127
        BOOST_CHECK_THROW((DXX_TEST_VALPTRIDX_IGNORE_RETURN(
128
                                (Objects.set_count(optimizer_hidden_variable<objnum_t>(MAX_OBJECTS + 1)), Objects.vmptr.end())
129
        )), valptridx_access_override::index_range_exception);
130
}
131
 
132
BOOST_AUTO_TEST_CASE(guarded_in_range)
133
{
134
        auto &&g = Objects.vmptr.check_untrusted(optimizer_hidden_variable<objnum_t>(0));
135
        optimizer_hidden_variable(g);
136
        /* Test that a `guarded` returned by `check_untrusted` on a valid
137
         * index throws if accessed without testing its validity.  A runtime
138
         * check on validity is mandatory.
139
         *
140
         * These exceptions are not configurable, so no test on
141
         * `report_error_uses_exception` is required.
142
         */
143
        BOOST_CHECK_THROW(DXX_TEST_VALPTRIDX_IGNORE_RETURN(*g), std::logic_error);
144
        /* Test its validity */
145
        BOOST_TEST(static_cast<bool>(g));
146
        /* Test that it can now be read successfully. */
147
        BOOST_CHECK_NO_THROW(DXX_TEST_VALPTRIDX_IGNORE_RETURN(*g));
148
}
149
 
150
BOOST_AUTO_TEST_CASE(guarded_out_of_range)
151
{
152
        auto &&g = Objects.vmptr.check_untrusted(optimizer_hidden_variable<objnum_t>(MAX_OBJECTS));
153
        optimizer_hidden_variable(g);
154
        /* Test that a `guarded` returned by `check_untrusted` on an invalid
155
         * index throws if accessed without testing its validity.
156
         *
157
         * Test its validity.
158
         *
159
         * Test that it still throws afterward.
160
         */
161
        BOOST_CHECK_THROW(DXX_TEST_VALPTRIDX_IGNORE_RETURN(*g), std::logic_error);
162
        BOOST_TEST(!static_cast<bool>(g));
163
        BOOST_CHECK_THROW(DXX_TEST_VALPTRIDX_IGNORE_RETURN(*g), std::logic_error);
164
}
165
 
166
BOOST_AUTO_TEST_CASE(idx_convert_check)
167
{
168
        using vo = valptridx<object>;
169
        BOOST_CHECK_NO_THROW(
170
                DXX_TEST_VALPTRIDX_IGNORE_RETURN(({
171
                        typename vo::imidx i(static_cast<objnum_t>(0));
172
                        typename vo::vmidx{i};
173
                        }))
174
        );
175
        typename vo::imidx i_none(static_cast<objnum_t>(~0));
176
        if (!valptridx_access_override::report_error_uses_exception::value)
177
                return;
178
        BOOST_CHECK_THROW(
179
                DXX_TEST_VALPTRIDX_IGNORE_RETURN(({
180
                        typename vo::vmidx{i_none};
181
                        })), valptridx_access_override::index_range_exception
182
        );
183
        BOOST_CHECK_THROW(
184
                DXX_TEST_VALPTRIDX_IGNORE_RETURN(({
185
                        typename vo::vmidx{optimizer_hidden_variable<objnum_t>(~0)};
186
                        })), valptridx_access_override::index_range_exception
187
        );
188
}
189
 
190
BOOST_AUTO_TEST_CASE(ptr_convert_check)
191
{
192
        using vo = valptridx<object>;
193
        typename vo::imptr i_none(nullptr);
194
        auto &&i_zero = Objects.imptr(optimizer_hidden_variable<objnum_t>(0));
195
        BOOST_CHECK_NO_THROW(
196
                DXX_TEST_VALPTRIDX_IGNORE_RETURN(({
197
                        typename vo::vmptr v_zero{i_zero};
198
                        v_zero.get_nonnull_pointer();
199
                        }))
200
        );
201
        if (!valptridx_access_override::report_error_uses_exception::value)
202
                return;
203
        BOOST_CHECK_THROW(
204
                DXX_TEST_VALPTRIDX_IGNORE_RETURN(({
205
                        typename vo::vmptr{i_none};
206
                        })), valptridx_access_override::null_pointer_exception
207
        );
208
        BOOST_CHECK_THROW(
209
                DXX_TEST_VALPTRIDX_IGNORE_RETURN(({
210
                        Objects.vmptr(optimizer_hidden_variable<object *>(nullptr));
211
                        })), valptridx_access_override::null_pointer_exception
212
        );
213
        BOOST_CHECK_THROW(
214
                DXX_TEST_VALPTRIDX_IGNORE_RETURN(({
215
                        i_none.get_nonnull_pointer();
216
                        })), valptridx_access_override::null_pointer_exception
217
        );
218
        auto &&pi_zero = Objects.vmptridx(optimizer_hidden_variable<objnum_t>(0));
219
        BOOST_CHECK_THROW(
220
                DXX_TEST_VALPTRIDX_IGNORE_RETURN(({
221
                        pi_zero.absolute_sibling(optimizer_hidden_variable<objnum_t>(Objects.size()));
222
                        })), valptridx_access_override::index_range_exception
223
        );
224
}
225
 
226
/* For each style selector, set a type.  Test that the type is used.
227
 * Reset to a different type.  Test that the second type is used.  Clear
228
 * the selector, so that any further use is an error.
229
 *
230
 * This combination verifies that the requested style is set, and that
231
 * the match is not an accident.  If the first test succeeded because
232
 * the style happened to match for the wrong reason, then redefining the
233
 * style would have no effect, and the second test would fail.
234
 */
235
 
236
/* Test DXX_VALPTRIDX_REPORT_ERROR_STYLE_default - the final fallback,
237
 * used only when everything else is unset.
238
 */
239
#undef DXX_VALPTRIDX_REPORT_ERROR_STYLE_default
240
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_default exception
241
 
242
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(const, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::exception);
243
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(mutable, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::exception);
244
 
245
#undef DXX_VALPTRIDX_REPORT_ERROR_STYLE_default
246
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_default undefined
247
 
248
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(const, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::undefined);
249
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(mutable, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::undefined);
250
 
251
#undef DXX_VALPTRIDX_REPORT_ERROR_STYLE_default
252
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_default        /* invalid mapping - force an error on use */
253
 
254
/* Test the const/mutable defaults.  These are the second lowest
255
 * priority, above only DXX_VALPTRIDX_REPORT_ERROR_STYLE_default.
256
 */
257
#undef DXX_VALPTRIDX_REPORT_ERROR_STYLE_const_default
258
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_const_default trap_terse
259
#undef DXX_VALPTRIDX_REPORT_ERROR_STYLE_mutable_default
260
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_mutable_default trap_verbose
261
 
262
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(const, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::trap_terse);
263
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(mutable, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::trap_verbose);
264
 
265
#undef DXX_VALPTRIDX_REPORT_ERROR_STYLE_const_default
266
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_const_default exception
267
#undef DXX_VALPTRIDX_REPORT_ERROR_STYLE_mutable_default
268
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_mutable_default trap_terse
269
 
270
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(const, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::exception);
271
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(mutable, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::trap_terse);
272
 
273
#undef DXX_VALPTRIDX_REPORT_ERROR_STYLE_const_default
274
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_const_default
275
#undef DXX_VALPTRIDX_REPORT_ERROR_STYLE_mutable_default
276
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_mutable_default
277
 
278
/* Test the type-specific default.  This is the third lowest priority.
279
 */
280
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_default_error_report_test      undefined
281
 
282
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(const, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::undefined);
283
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(mutable, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::undefined);
284
 
285
#undef DXX_VALPTRIDX_REPORT_ERROR_STYLE_default_error_report_test
286
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_default_error_report_test      exception
287
 
288
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(const, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::exception);
289
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(mutable, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::exception);
290
 
291
#undef DXX_VALPTRIDX_REPORT_ERROR_STYLE_default_error_report_test
292
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_default_error_report_test
293
 
294
/* Test the const/mutable type-specific.  These are the highest
295
 * priority.
296
 */
297
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_const_error_report_test        trap_terse
298
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_mutable_error_report_test      trap_verbose
299
 
300
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(const, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::trap_terse);
301
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(mutable, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::trap_verbose);
302
 
303
#undef DXX_VALPTRIDX_REPORT_ERROR_STYLE_const_error_report_test
304
#undef DXX_VALPTRIDX_REPORT_ERROR_STYLE_mutable_error_report_test
305
 
306
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_const_error_report_test        exception
307
#define DXX_VALPTRIDX_REPORT_ERROR_STYLE_mutable_error_report_test      undefined
308
 
309
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(const, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::exception);
310
static_assert(valptridx_detail::untyped_utilities::error_style_dispatch<DXX_VALPTRIDX_ERROR_STYLE_DISPATCH_PARAMETERS(mutable, error_report_test)>::value == valptridx_detail::untyped_utilities::report_error_style::undefined);