From 078aa488799d2c56310677681f3803c3e881764b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 14 Sep 2026 23:34:12 +0200 Subject: [PATCH] Library: verify the new cyclicWrap library function The implementation should cover all integral data types, both signed and signed, over the entire value domain. Verify that by testing the bounds and the complex computation path --- tests/15library.tests | 5 ++ tests/lib/cyclic-wrap-test.cpp | 144 +++++++++++++++++++++++++++++++++ wiki/thinkPad.ichthyo.mm | 87 +++++++++++++++++--- 3 files changed, 225 insertions(+), 11 deletions(-) create mode 100644 tests/lib/cyclic-wrap-test.cpp diff --git a/tests/15library.tests b/tests/15library.tests index 74f985dc3..3b629393d 100644 --- a/tests/15library.tests +++ b/tests/15library.tests @@ -53,6 +53,11 @@ return: 0 END +TEST "Cyclic wrapping number domain" CyclicWrap_test < + +  **Lumiera** is free software; you can redistribute it and/or modify it +  under the terms of the GNU General Public License as published by the +  Free Software Foundation; either version 2 of the License, or (at your +  option) any later version. See the file COPYING for further details. + +* *****************************************************************/ + +/** @file util-floordiv-test.cpp + ** unit test \ref CyclicWrap_test + */ + + +#include "test/run.hpp" +#include "lib/util-quant.hpp" +#include "lib/util.hpp" +#include "test/diagnostic-output.hpp"//////////////////TODO +//#include "lib/format-cout.hpp" +//#include "lib/format-string.hpp" + +using ::Test; +//using util::isnil; +//using util::_Fmt; +using util::isLimited; + + +namespace util { +namespace test { + + + + namespace{ // Test helpers... + + template + constexpr NUM _MAX = std::numeric_limits::max(); + + template + constexpr NUM _MIN = std::numeric_limits::lowest(); + + } // (End) Test helpers + + + + /******************************************************************//** + * @test Demonstrate and verify a cyclic wrapping numeric domain. + * - show the wrapping behaviour with simple numbers + * - verify the behaviour pattern for all integer types (signed / unsigned) + * - verify the computation works at the very bounds of the domain + * - verify the most difficult path with a negative minVal, + * and the smallest number in the domain + * @todo add coverage for floating-point numbers + * @see util::cyclicWrap + * @see parameter-scale-test.cpp + */ + class CyclicWrap_test : public Test + { + + virtual void + run (Arg) + { + simpleDemonstration(); + + verifyIntegerTypes(); + verifyIntegerTypes(); + verifyIntegerTypes(); + verifyIntegerTypes(); + verifyIntegerTypes (); + verifyIntegerTypes(); + verifyIntegerTypes (); + verifyIntegerTypes(); + verifyIntegerTypes (); + verifyIntegerTypes(); + } + + + void + simpleDemonstration () + { + CHECK (10 == cyclicWrap (10,10,15)); + CHECK (11 == cyclicWrap (11,10,15)); + CHECK (12 == cyclicWrap (12,10,15)); + CHECK (13 == cyclicWrap (13,10,15)); + CHECK (14 == cyclicWrap (14,10,15)); + CHECK (10 == cyclicWrap (15,10,15)); + CHECK (11 == cyclicWrap (16,10,15)); + CHECK (12 == cyclicWrap (17,10,15)); + CHECK (13 == cyclicWrap (18,10,15)); + CHECK (14 == cyclicWrap (19,10,15)); + CHECK (10 == cyclicWrap (20,10,15)); + + CHECK (10 == cyclicWrap ( 0,10,15)); + CHECK (14 == cyclicWrap (-1,10,15)); + } + + + template + void + verifyIntegerTypes () + { + const I LOWER(-100); // note: expected to wrap for unsigned types + const I UPPER(LOWER+5); + + auto cyc = [&](I val){ return cyclicWrap (I(val), LOWER,UPPER); }; + + CHECK (LOWER == cyc(LOWER+0) ); + CHECK (LOWER+1 == cyc(LOWER+1) ); + CHECK (LOWER+2 == cyc(LOWER+2) ); + CHECK (LOWER+3 == cyc(LOWER+3) ); + CHECK (LOWER+4 == cyc(LOWER+4) ); + CHECK (LOWER == cyc(LOWER+5) ); + + CHECK (LOWER == cyc(LOWER-5) ); + CHECK (LOWER+1 == cyc(LOWER-4) ); + CHECK (LOWER+2 == cyc(LOWER-3) ); + CHECK (LOWER+3 == cyc(LOWER-2) ); + CHECK (LOWER+4 == cyc(LOWER-1) ); + + + CHECK (isLimited (LOWER, cyc(_MAX), UPPER)); + CHECK (isLimited (LOWER, cyc(_MIN), UPPER)); + + CHECK (isLimited (LOWER, cyc(_MAX-1), UPPER)); + CHECK (isLimited (LOWER, cyc(_MIN+1), UPPER)); + + I dist = LOWER - _MIN; // guaranteed to be positive and representable in-domain + I step = (dist / 5) * 5; // the next applicable grid point + I excess = dist - step; + I offset = 5 - excess; // flip orientation (since the input val lies below LOWER) + + CHECK (LOWER + offset == cyc(_MIN) ); + } + }; + + + + LAUNCHER (CyclicWrap_test, "unit common"); + + +}} // namespace util::test diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 9d26551c6..adbfa8b6b 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -86141,7 +86141,7 @@ class ScaleRegistry - + @@ -86158,7 +86158,8 @@ class ScaleRegistry

- + + @@ -86257,7 +86258,7 @@ class ScaleRegistry - + @@ -86337,7 +86338,7 @@ class ScaleRegistry - + @@ -86527,7 +86528,7 @@ class ScaleRegistry

- + @@ -86769,13 +86770,14 @@ Prop.1: dist%3 1 2 0 1 2 0

- + +
- + @@ -86784,7 +86786,7 @@ Prop.1: dist%3 1 2 0 1 2 0

- +
@@ -86806,13 +86808,14 @@ Prop.1: dist%3 1 2 0 1 2 0
- + +
- + @@ -86822,8 +86825,70 @@ Prop.1: dist%3 1 2 0 1 2 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ .... ich könnte mir denken, daß mancher Leser das Konzept nicht gleich versteht, deshalb ist ein solches einfaches Beispiel nie verkehrt +

+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + -