Affix
view release on metacpan or search on metacpan
t/012_enum.t view on Meta::CPAN
[ TEST_A => 0 ], [ TEST_B => 10 ], 'TEST_C', # Should be 11
[ TEST_D => 0x20 ], # Should be 32
[ TEST_E => 'TEST_B' ] # Should be 10
]
),
'typedef Enum executed';
# Verify constants were exported to this namespace
ok defined &TEST_A, 'Constant TEST_A exported';
ok defined &TEST_B, 'Constant TEST_B exported';
ok defined &TEST_C, 'Constant TEST_C exported';
# Verify values
is TEST_A(), 0, 'Explicit value (0)';
is TEST_B(), 10, 'Explicit value (10)';
is TEST_C(), 11, 'Auto-increment value (10 + 1 = 11)';
is TEST_D(), 32, 'Hex value (0x20)';
is TEST_E(), 10, 'Back-reference value (== TEST_B)';
};
subtest 'C Integration & Dualvars' => sub {
# Define the Enum matching the C library
typedef MachineState => Enum [
[ STATE_START => 0 ], [ STATE_RUNNING => 10 ], 'STATE_PAUSED', # 11
[ STATE_STOPPED => 20 ], [ STATE_ERROR => 99 ]
];
# Bind functions
isa_ok my $check = wrap( $lib, 'check_state', ['@MachineState'] => Int ), ['Affix'];
isa_ok my $next = wrap( $lib, 'get_next_state', ['@MachineState'] => '@MachineState' ), ['Affix'];
subtest 'Passing Constants to C' => sub {
# Pass the bareword constant
is $check->( STATE_RUNNING() ), 1, 'Passed constant STATE_RUNNING (10) ok';
is $check->( STATE_PAUSED() ), 2, 'Passed constant STATE_PAUSED (11) ok';
# Pass raw integer
is $check->(10), 1, 'Passed raw integer 10 ok';
};
subtest 'Returning Dualvars from C' => sub {
# Case 1: START -> RUNNING
my $val = $next->( STATE_START() );
# Check Numeric Value
is 0 + $val, 10, 'Numeric value is 10';
ok $val == STATE_RUNNING(), 'Numeric equality with constant';
# Check String Value (Dualvar)
is "$val", 'STATE_RUNNING', 'String value is "STATE_RUNNING"';
ok $val eq 'STATE_RUNNING', 'String equality';
# Case 2: RUNNING -> PAUSED
my $val2 = $next->( STATE_RUNNING() );
is 0 + $val2, 11, 'Numeric value is 11';
is "$val2", 'STATE_PAUSED', 'String value is "STATE_PAUSED"';
};
subtest 'Unknown Values' => sub {
# Create a function that returns a value NOT in our enum definition
# (Simulating C library adding a new flag we don't know about yet)
my $raw_lib = compile_ok(<<'END_RAW');
#include "std.h"
//ext: .c
DLLEXPORT int get_unknown() { return 555; }
END_RAW
my $get_unknown = wrap( $raw_lib, 'get_unknown', [] => MachineState() );
my $val = $get_unknown->();
is 0 + $val, 555, 'Unknown integer value preserved';
# Behavior for unknown strings depends on impl, usually just the number as string
# or undef string slot. Usually sv_setiv sets the IV, sv_setpv is skipped.
# So "$val" should be "555".
is "$val", '555', 'Stringification of unknown enum value falls back to number';
};
};
{
package Other::Scope;
use Affix;
use Test2::Tools::Affix qw[ok is];
sub run_test {
Affix::typedef( ScopedEnum => Affix::Enum( [ [ SCOPED_A => 99 ] ] ) );
ok defined &SCOPED_A, 'Constant exported to Other::Scope';
is SCOPED_A(), 99, 'Constant value correct in Other::Scope';
}
}
subtest 'Namespace Isolation' => sub {
Other::Scope::run_test();
ok !defined &SCOPED_A, 'Constant NOT leaked to main package';
};
subtest 'Bitwise Shift' => sub {
my $e = Enum [ [ BIT_0 => '1 << 0' ], [ BIT_1 => '1 << 1' ], [ BIT_5 => '1 << 5' ], [ RSHIFT => '32 >> 2' ] ];
my ( $c, $v ) = $e->resolve();
is $c->{BIT_0}, 1, '1 << 0';
is $c->{BIT_1}, 2, '1 << 1';
is $c->{BIT_5}, 32, '1 << 5';
is $c->{RSHIFT}, 8, '32 >> 2';
};
subtest 'Unary Operators' => sub {
my $e = Enum [ [ NEG => '-5' ], [ NOT => '!0' ], [ BIT_NOT => '~0' ], [ MASK => '~(1 << 2)' ] ];
my ( $c, $v ) = $e->resolve();
is $c->{NEG}, -5, 'Unary minus';
is $c->{NOT}, 1, 'Logical NOT (!0)';
# C enums are signed int. ~0 is -1.
is $c->{BIT_NOT}, -1, 'Bitwise NOT (~0) is -1';
# ~(1<<2) = ~4. In signed 32/64-bit, this is -5.
is $c->{MASK}, -5, 'Complex unary/shift (~(1<<2)) is -5';
};
subtest 'Logical and Ternary' => sub {
my $e = Enum [
[ TRUE_VAL => 10 ],
[ FALSE_VAL => 20 ],
[ TERNARY_T => '1 ? TRUE_VAL : FALSE_VAL' ],
[ TERNARY_F => '0 ? TRUE_VAL : FALSE_VAL' ],
[ LOGIC_AND => '1 && 1' ],
[ LOGIC_OR => '0 || 0' ],
[ CMP_LESS => '10 < 20' ]
( run in 0.583 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )