Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  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);
  311.