Skip to content

Commit e662de5

Browse files
Add test for cross-module getter→setter enum roundtrip
The existing test_cross_module_scoped_enum_imports test had a gap: it didn't test the scenario where a class in module B uses both getter and setter methods for an enum defined in module A. This is the exact pattern that failed in pyOpenMS: s.setType(s.getType()) # Cross-module roundtrip Changes: - Add StatusTracker class to EnumConsumer with getter/setter for enums from EnumProvider (both Task::TaskStatus and Priority) - Add Runtime Test 8 that validates tracker.setX(tracker.getX()) works correctly across module boundaries - Update test assertions to check for _get_scoped_enum_class() pattern instead of the old globals().get() pattern Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 7597114 commit e662de5

File tree

3 files changed

+62
-5
lines changed

3 files changed

+62
-5
lines changed

tests/test_code_generator.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -861,13 +861,14 @@ def test_cross_module_scoped_enum_imports(tmpdir):
861861
f"EnumConsumer.pyx content:\n{consumer_pyx}"
862862
)
863863

864-
# Test 2: Verify isinstance checks use globals().get() for late binding
865-
assert "globals().get('_PyTask_TaskStatus'" in consumer_pyx, (
866-
f"Expected isinstance check with globals().get('_PyTask_TaskStatus', int) for wrap-attach enum.\n"
864+
# Test 2: Verify isinstance checks use _get_scoped_enum_class() helper for late binding
865+
# The helper looks up enums via registry and sys.modules for cross-module support
866+
assert "_get_scoped_enum_class('_PyTask_TaskStatus')" in consumer_pyx, (
867+
f"Expected isinstance check with _get_scoped_enum_class('_PyTask_TaskStatus') for wrap-attach enum.\n"
867868
f"EnumConsumer.pyx content:\n{consumer_pyx}"
868869
)
869-
assert "globals().get('Priority'" in consumer_pyx, (
870-
f"Expected isinstance check with globals().get('Priority', int) for non-wrap-attach enum.\n"
870+
assert "_get_scoped_enum_class('Priority')" in consumer_pyx, (
871+
f"Expected isinstance check with _get_scoped_enum_class('Priority') for non-wrap-attach enum.\n"
871872
f"EnumConsumer.pyx content:\n{consumer_pyx}"
872873
)
873874

@@ -976,6 +977,27 @@ def test_cross_module_scoped_enum_imports(tmpdir):
976977
except AssertionError as e:
977978
assert "wrong type" in str(e)
978979

980+
# Runtime Test 8: Cross-module getter→setter roundtrip (the pyOpenMS scenario)
981+
# This tests that a class in module B can use getX()/setX() with an enum from module A
982+
# where setX(getX()) works correctly - this was the missing test case.
983+
tracker = EnumConsumer.StatusTracker()
984+
985+
# Test with class-attached enum (Task::TaskStatus)
986+
assert tracker.getStatus() == EnumProvider.Task.TaskStatus.PENDING
987+
tracker.setStatus(EnumProvider.Task.TaskStatus.RUNNING)
988+
assert tracker.getStatus() == EnumProvider.Task.TaskStatus.RUNNING
989+
# THE KEY TEST: getter→setter roundtrip across module boundaries
990+
tracker.setStatus(tracker.getStatus()) # This is what failed in pyOpenMS!
991+
assert tracker.getStatus() == EnumProvider.Task.TaskStatus.RUNNING
992+
993+
# Test with standalone enum (Priority)
994+
assert tracker.getPriority() == EnumProvider.Priority.LOW
995+
tracker.setPriority(EnumProvider.Priority.HIGH)
996+
assert tracker.getPriority() == EnumProvider.Priority.HIGH
997+
# THE KEY TEST: getter→setter roundtrip across module boundaries
998+
tracker.setPriority(tracker.getPriority()) # This is what failed in pyOpenMS!
999+
assert tracker.getPriority() == EnumProvider.Priority.HIGH
1000+
9791001
print("Test passed: Cross-module scoped enum imports work correctly at runtime!")
9801002

9811003
finally:

tests/test_files/enum_cross_module/EnumConsumer.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,29 @@ class TaskRunner {
3535
}
3636
};
3737

38+
/**
39+
* StatusTracker: Tests cross-module getter→setter roundtrip.
40+
*
41+
* This class lives in EnumConsumer module but uses enums from EnumProvider
42+
* for BOTH getter AND setter methods. This tests the scenario where:
43+
* tracker.setStatus(tracker.getStatus())
44+
* must work correctly across module boundaries.
45+
*/
46+
class StatusTracker {
47+
public:
48+
StatusTracker() : status_(Task::TaskStatus::PENDING), priority_(Priority::LOW) {}
49+
50+
// Getter and setter for class-attached enum (Task::TaskStatus)
51+
void setStatus(Task::TaskStatus s) { status_ = s; }
52+
Task::TaskStatus getStatus() const { return status_; }
53+
54+
// Getter and setter for standalone enum (Priority)
55+
void setPriority(Priority p) { priority_ = p; }
56+
Priority getPriority() const { return priority_; }
57+
58+
private:
59+
Task::TaskStatus status_;
60+
Priority priority_;
61+
};
62+
3863
#endif // ENUM_CONSUMER_HPP

tests/test_files/enum_cross_module/EnumConsumer.pxd

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,13 @@ cdef extern from "EnumConsumer.hpp":
1616
bool isCompleted(Task_TaskStatus s)
1717
Priority getDefaultPriority()
1818
Task_TaskStatus getDefaultStatus()
19+
20+
# StatusTracker: Tests cross-module getter→setter roundtrip
21+
# This class has getter AND setter for enums from EnumProvider,
22+
# testing that tracker.setStatus(tracker.getStatus()) works.
23+
cdef cppclass StatusTracker:
24+
StatusTracker()
25+
void setStatus(Task_TaskStatus s)
26+
Task_TaskStatus getStatus()
27+
void setPriority(Priority p)
28+
Priority getPriority()

0 commit comments

Comments
 (0)