mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-07-30 16:26:28 +08:00
Add tests for #421: switch with type_conversion lifetime bug
Add both a compiled C++ test (with registered type_conversion) and a pure ChaiScript test (with dynamic objects and custom == operator) to verify that switch case comparisons properly manage object lifetimes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
78d2de0ccf
commit
a329be16ad
@ -1304,3 +1304,97 @@ TEST_CASE("Test if non copyable/movable types can be registered") {
|
|||||||
chai.add(chaiscript::user_type<Nothing>(), "Nothing");
|
chai.add(chaiscript::user_type<Nothing>(), "Nothing");
|
||||||
chai.add(chaiscript::constructor<Nothing()>(), "Nothing");
|
chai.add(chaiscript::constructor<Nothing()>(), "Nothing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue #421: Class with type_conversion from int and "==" operator
|
||||||
|
// causes switch statement to compare destroyed objects.
|
||||||
|
// The switch case comparison must use Function_Push_Pop to properly
|
||||||
|
// manage the lifetime of temporaries created by type conversions.
|
||||||
|
TEST_CASE("Issue #421 - Switch with type_conversion does not compare destroyed objects") {
|
||||||
|
struct MyType {
|
||||||
|
int value;
|
||||||
|
explicit MyType(int v) : value(v) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||||
|
chai.add(chaiscript::user_type<MyType>(), "MyType");
|
||||||
|
chai.add(chaiscript::constructor<MyType(int)>(), "MyType");
|
||||||
|
chai.add(chaiscript::fun(&MyType::value), "value");
|
||||||
|
chai.add(chaiscript::fun([](const MyType &a, const MyType &b) { return a.value == b.value; }), "==");
|
||||||
|
chai.add(chaiscript::type_conversion<int, MyType>([](const int &i) { return MyType(i); }));
|
||||||
|
|
||||||
|
// Test switch with type conversion - the case integer literals must be
|
||||||
|
// converted to MyType via the registered conversion before comparison.
|
||||||
|
// Without Function_Push_Pop, the converted temporaries may be destroyed
|
||||||
|
// before the == operator can compare them.
|
||||||
|
CHECK(chai.eval<int>(R"({
|
||||||
|
var result = 0
|
||||||
|
var obj = MyType(2)
|
||||||
|
switch(obj) {
|
||||||
|
case (1) {
|
||||||
|
result = 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case (2) {
|
||||||
|
result = 2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case (3) {
|
||||||
|
result = 3
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
})") == 2);
|
||||||
|
|
||||||
|
// Test fall-through with type conversion
|
||||||
|
CHECK(chai.eval<int>(R"({
|
||||||
|
var total = 0
|
||||||
|
var obj = MyType(2)
|
||||||
|
switch(obj) {
|
||||||
|
case (1) {
|
||||||
|
total += 1
|
||||||
|
}
|
||||||
|
case (2) {
|
||||||
|
total += 2
|
||||||
|
}
|
||||||
|
case (3) {
|
||||||
|
total += 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
total
|
||||||
|
})") == 6);
|
||||||
|
|
||||||
|
// Test matching the first case
|
||||||
|
CHECK(chai.eval<int>(R"({
|
||||||
|
var result = 0
|
||||||
|
var obj = MyType(1)
|
||||||
|
switch(obj) {
|
||||||
|
case (1) {
|
||||||
|
result = 10
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case (2) {
|
||||||
|
result = 20
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
})") == 10);
|
||||||
|
|
||||||
|
// Test no match
|
||||||
|
CHECK(chai.eval<int>(R"({
|
||||||
|
var result = 0
|
||||||
|
var obj = MyType(5)
|
||||||
|
switch(obj) {
|
||||||
|
case (1) {
|
||||||
|
result = 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case (2) {
|
||||||
|
result = 2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
})") == 0);
|
||||||
|
}
|
||||||
|
|||||||
50
unittests/switch_type_conversion.chai
Normal file
50
unittests/switch_type_conversion.chai
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Test for issue #421: switch statement with custom == operator on
|
||||||
|
// dynamic objects must properly manage object lifetimes during
|
||||||
|
// case comparisons.
|
||||||
|
|
||||||
|
class MyType {
|
||||||
|
var value
|
||||||
|
def MyType(v) { this.value = v }
|
||||||
|
}
|
||||||
|
|
||||||
|
def `==`(a, b) : a.is_type("MyType") && b.is_type("MyType") {
|
||||||
|
return a.value == b.value
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = 0
|
||||||
|
var obj = MyType(2)
|
||||||
|
|
||||||
|
switch(obj) {
|
||||||
|
case (MyType(1)) {
|
||||||
|
result = 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case (MyType(2)) {
|
||||||
|
result = 2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case (MyType(3)) {
|
||||||
|
result = 3
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal(result, 2)
|
||||||
|
|
||||||
|
// Also test fall-through with custom == operator
|
||||||
|
var total = 0
|
||||||
|
var obj2 = MyType(2)
|
||||||
|
|
||||||
|
switch(obj2) {
|
||||||
|
case (MyType(1)) {
|
||||||
|
total += 1
|
||||||
|
}
|
||||||
|
case (MyType(2)) {
|
||||||
|
total += 2
|
||||||
|
}
|
||||||
|
case (MyType(3)) {
|
||||||
|
total += 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal(total, 6)
|
||||||
Loading…
x
Reference in New Issue
Block a user