2026-07-03 19:55:55 +02:00
/*
ParameterDomain ( Test ) - document the handling of parameter type domain
Copyright ( C )
2026 , Hermann Vosseler < Ichthyostega @ web . de >
* * 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 parameter-domain-test.cpp
* * unit test \ ref ParameterDomain_test
*/
# include "test/run.hpp"
//#include "test/test-helper.hpp"
# include "lib/par/domain.hpp"
2026-07-19 23:44:30 +02:00
# include "test/diagnostic-output.hpp" ////////////TODO
2026-07-03 19:55:55 +02:00
//#include <utility>
//#include <string>
//#include <vector>
2026-07-22 22:17:04 +02:00
# include <concepts>
2026-07-03 19:55:55 +02:00
//using std::string;
//using std::vector;
//using std::swap;
namespace lib {
namespace par {
namespace test {
// using lumiera::error::LUMIERA_ERROR_LOGIC;
2026-07-22 22:17:04 +02:00
using std : : floating_point ;
2026-07-03 19:55:55 +02:00
namespace { //Test fixture....
2026-07-22 22:17:04 +02:00
template < typename NUM >
constexpr NUM _MAX = std : : numeric_limits < NUM > : : max ( ) ;
2026-07-03 19:55:55 +02:00
2026-07-22 22:17:04 +02:00
template < typename NUM >
constexpr NUM _MIN = std : : numeric_limits < NUM > : : lowest ( ) ;
template < floating_point FLO >
constexpr FLO _EPSILON = std : : numeric_limits < FLO > : : epsilon ( ) ;
2026-07-03 19:55:55 +02:00
} //(End)Test fixture
/**************************************************************************/ /**
* @ test cover properties of generic parameter containers .
*/
class ParameterDomain_test : public Test
{
virtual void
run ( Arg )
{
2026-07-05 22:12:18 +02:00
seedRand ( ) ;
2026-07-22 22:17:04 +02:00
2026-07-05 22:12:18 +02:00
basics ( ) ;
2026-07-20 23:12:24 +02:00
verify_valueLimits ( ) ;
2026-07-19 23:44:30 +02:00
verify_valueAccess ( ) ;
2026-07-25 21:52:51 +02:00
verify_valueSetting ( ) ;
verify_opaqueAssign ( ) ;
2026-07-03 19:55:55 +02:00
}
void
2026-07-05 22:12:18 +02:00
basics ( )
2026-07-03 19:55:55 +02:00
{
}
2026-07-22 22:17:04 +02:00
/** @test base operation to bracket a given value
* so that it fits within another target type ' s value domain .
* @ note properly handles the signed vs . unsigned mismatch , so that
* conversion from signed to unsigned can not wrap .
*/
2026-07-20 23:12:24 +02:00
void
verify_valueLimits ( )
{
2026-07-22 22:17:04 +02:00
// Generic check if the first (target) type can hold
// only a limited part of the second (source) type's domain
CHECK ( ( sub_domain < uint , int > = = true ) ) ;
CHECK ( ( sub_domain < int , uint > = = true ) ) ;
CHECK ( ( sub_domain < short , long > = = true ) ) ;
CHECK ( ( sub_domain < long , short > = = false ) ) ;
CHECK ( ( sub_domain < float , double > = = true ) ) ;
CHECK ( ( sub_domain < double , float > = = false ) ) ;
// Limit a value to within a target type's domain
// (without actually converting into the target type)
CHECK ( preClamp < int > ( 23 ) = = 23 ) ;
CHECK ( preClamp < int > ( - 55 ) = = - 55 ) ;
CHECK ( preClamp < uint > ( 23 ) = = 23 ) ;
CHECK ( preClamp < uint > ( - 55 ) = = 0 ) ;
CHECK ( preClamp < short > ( _MAX < int64_t > ) = = 32767 ) ;
CHECK ( preClamp < short > ( _MIN < int64_t > ) = = - 32768 ) ;
CHECK ( preClamp < ushort > ( _MAX < float > ) = = 65535 ) ;
CHECK ( preClamp < ushort > ( _MIN < float > ) = = 0 ) ;
// the return value has the same type as the argument...
CHECK ( preClamp < float > ( _MAX < uint64_t > ) = = _MAX < uint64_t > ) ;
CHECK ( preClamp < float > ( _MIN < double > ) = = double ( _MIN < float > ) ) ;
// Warning: the following is not standard C++, yet supported on GCC / CLang / libstdc++
static_assert ( _MAX < float > < _MAX < unsigned __int128 > ) ;
CHECK ( float ( _MAX < unsigned __int128 > ) = = " inf " _expect ) ;
CHECK ( ( unsigned __int128 ) _MAX < float > = = " 340282346638528859811704183484516925440 " _expect ) ;
CHECK ( preClamp < float > ( _MAX < unsigned __int128 > ) = = ( unsigned __int128 ) _MAX < float > ) ;
// Note: a trigger at 0.5+ε is built into the clamp towards bool
CHECK ( preClamp < bool > ( 0.5 ) = = 0 ) ;
CHECK ( preClamp < bool > ( 0.5 + _EPSILON < double > ) = = 1 ) ;
CHECK ( preClamp < bool > ( _MIN < double > ) = = 0 ) ;
// Systematic coverage of signed ⟷ unsigned
CHECK ( preClamp < int8_t > ( _MAX < int16_t > ) = = 127 ) ;
CHECK ( preClamp < int8_t > ( int16_t { 0 } ) = = 0 ) ;
CHECK ( preClamp < int8_t > ( _MIN < int16_t > ) = = - 128 ) ;
CHECK ( preClamp < int8_t > ( _MAX < uint16_t > ) = = 127 ) ;
CHECK ( preClamp < int8_t > ( _MIN < uint16_t > ) = = 0 ) ;
CHECK ( preClamp < uint8_t > ( _MAX < int16_t > ) = = 255 ) ;
CHECK ( preClamp < uint8_t > ( int16_t { 0 } ) = = 0 ) ;
CHECK ( preClamp < uint8_t > ( _MIN < int16_t > ) = = 0 ) ;
CHECK ( preClamp < int16_t > ( _MAX < int8_t > ) = = 127 ) ;
CHECK ( preClamp < int16_t > ( int8_t { 0 } ) = = 0 ) ;
CHECK ( preClamp < int16_t > ( _MIN < int8_t > ) = = - 128 ) ;
CHECK ( preClamp < int16_t > ( _MAX < uint8_t > ) = = 255 ) ;
CHECK ( preClamp < int16_t > ( _MIN < uint8_t > ) = = 0 ) ;
CHECK ( preClamp < uint16_t > ( _MAX < int8_t > ) = = 127 ) ;
CHECK ( preClamp < uint16_t > ( int8_t { 0 } ) = = 0 ) ;
CHECK ( preClamp < uint16_t > ( _MIN < int8_t > ) = = 0 ) ;
CHECK ( preClamp < int8_t > ( _MAX < int8_t > ) = = 127 ) ;
CHECK ( preClamp < int8_t > ( int8_t { 0 } ) = = 0 ) ;
CHECK ( preClamp < int8_t > ( _MIN < int8_t > ) = = - 128 ) ;
CHECK ( preClamp < int8_t > ( _MAX < uint8_t > ) = = 127 ) ;
CHECK ( preClamp < int8_t > ( _MIN < uint8_t > ) = = 0 ) ;
CHECK ( preClamp < uint8_t > ( _MAX < int8_t > ) = = 127 ) ;
CHECK ( preClamp < uint8_t > ( int8_t { 0 } ) = = 0 ) ;
CHECK ( preClamp < uint8_t > ( _MIN < int8_t > ) = = 0 ) ;
2026-07-20 23:12:24 +02:00
}
2026-07-22 22:17:04 +02:00
/** @test base function to access the contents of an opaque buffer
* with known type , and convert into another target type .
2026-08-30 23:35:54 +02:00
* - the base interface # Domain represents an opaque type
* - it exposes # TypeHandler interfaces for a fixed selection
* of common elementary # BaseTypes
* - here we use a ` BaseDomain < int > ` as actual implementation ,
* yet knowledge regarding the type ` int ` is erased and any
* access is based solely on a ` Domain & `
* - an opaque source ValBuf is passed explicitly
* @ remark this covers the value access capability of a
* type handler interface , working on external storage .
2026-07-22 22:17:04 +02:00
*/
2026-07-03 19:55:55 +02:00
void
2026-07-19 23:44:30 +02:00
verify_valueAccess ( )
2026-07-03 19:55:55 +02:00
{
2026-07-05 22:12:18 +02:00
BaseDomain < int > domInt ;
2026-08-31 23:17:32 +02:00
SHOW_EXPR ( sizeof ( BaseDomain < int > ) ) ///////////////////////////////////////TODO this should be only one »slot«, but is actually quite large, due to using multiple inheritance in the Domain interface. /////OOO fix that!
2026-07-25 21:52:51 +02:00
Domain & dom { domInt } ;
2026-07-05 22:12:18 +02:00
2026-07-25 21:52:51 +02:00
int val = 1 + rani ( 1000 ) ;
ValBuff & src = asValBuff ( val ) ;
2026-07-05 22:12:18 +02:00
uint target1 { 0 } ;
CHECK ( not target1 ) ;
2026-07-25 21:52:51 +02:00
TypeHandler < uint > & hu { dom } ;
hu . extractAs ( target1 , src ) ;
CHECK ( target1 = = uint ( val ) ) ;
2026-07-19 23:44:30 +02:00
float target2 { 0 } ;
2026-07-25 21:52:51 +02:00
TypeHandler < float > & hf { dom } ;
hf . extractAs ( target2 , src ) ;
CHECK ( target2 = = float ( val ) ) ;
2026-07-22 22:17:04 +02:00
// value clamped to target domain...
2026-07-25 21:52:51 +02:00
val = _MIN < int > ;
2026-07-22 22:17:04 +02:00
uint64_t target3 { 55 } ;
2026-07-25 21:52:51 +02:00
TypeHandler < uint64_t > & hu64 { dom } ;
hu64 . extractAs ( target3 , src ) ;
2026-07-22 22:17:04 +02:00
CHECK ( target3 = = _MIN < uint64_t > ) ;
2026-07-03 19:55:55 +02:00
}
2026-07-25 21:52:51 +02:00
/** @test base function to assign a directly given data value
* into an opaque buffer with known ( yet different ) type .
2026-08-30 23:35:54 +02:00
* @ remark since the type handler interface covers both reading
* and writing , here the roles are reversed here , so that the
* target of the assignment is the opaque buffer , whose actual
* type remains hidden behind the # Domain interface .
2026-07-25 21:52:51 +02:00
*/
void
verify_valueSetting ( )
{
BaseDomain < int > domInt ;
Domain & dom { domInt } ;
int val_in_buff = 0 ;
ValBuff & target = asValBuff ( val_in_buff ) ;
uint src1 = 1 + rani ( 1000 ) ;
TypeHandler < uint > & hu { dom } ;
hu . conform ( target , src1 ) ;
CHECK ( val_in_buff = = int ( src1 ) ) ;
double src2 = ranRange ( 1 , 100 ) ;
CHECK ( 1 < = src2 and src2 < 100 ) ;
TypeHandler < double > & hd { dom } ;
hd . conform ( target , src2 ) ;
CHECK ( val_in_buff = = int ( floor ( src2 ) ) ) ;
// value clamped to target domain...
auto mini = _MIN < int64_t > ;
TypeHandler < int64_t > & h64 { dom } ;
h64 . conform ( target , mini ) ;
CHECK ( val_in_buff = = _MIN < int > ) ;
}
/** @test value transfer between opaque buffers with double-dispatch.
* - use several typed values , yet access these only marked as ` ValBuff `
* - the call must be passed through _two virtual functions_ , in order
* to re - gain the fully typed context ; this is the » visitor pattern «
* @ remark the API might seem bewildering ; this is due to passing both source
* and target as reference to _some value buffer_ , since this API describes
* only a data type disposition , while the actual data storage is defined
* as derived parameter data type .
*/
void
verify_opaqueAssign ( )
{
double double_val = ranRange ( 2 , 100 ) ;
int64_t i64_val { 0 } ;
bool boo { false } ;
BaseDomain < double > ddom ;
BaseDomain < int64_t > idom ;
BaseDomain < bool > bdom ;
Domain & d1 { ddom } ;
Domain & d3 { bdom } ;
CHECK ( i64_val = = 0 ) ;
d1 . transferTo ( asValBuff ( double_val ) , idom , asValBuff ( i64_val ) ) ;
CHECK ( i64_val = = int64_t ( floor ( double_val ) ) ) ;
CHECK ( not boo ) ;
d1 . transferTo ( asValBuff ( double_val ) , bdom , asValBuff ( boo ) ) ;
CHECK ( boo ) ;
CHECK ( double_val ! = 1.0 ) ;
d3 . transferTo ( asValBuff ( boo ) , ddom , asValBuff ( double_val ) ) ;
CHECK ( double_val = = 1.0 ) ;
}
2026-07-03 19:55:55 +02:00
} ;
/** Register this test class... */
LAUNCHER ( ParameterDomain_test , " unit lib " ) ;
} } } // namespace lib::par::test