Migrate base RulesEngineInternal operator unit tests to JSON predicate fixtures#6885
Conversation
…tures
Convert the hand-written operator unit tests for operators available at the
string+array level into declarative JSON predicate fixtures sharing khepri's
conformance format, run by a shared runner that auto-discovers every file in
PredicateFixtures/. `expected` is a khepri-compatible superset (Bool or
{ "error": ... }) plus optional `description` and `expectedWarnings`.
Adds a test-only Value: Decodable conformance so predicates and variables
decode straight into the engine's value model; production Value is unchanged.
Tests that can't be expressed as predicate->Bool stay in Swift; ValueTests
untouched. Test-only change.
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 40901e5)
| let id: String | ||
| let description: String? | ||
| let predicate: Value | ||
| let variables: [String: Value] | ||
| let expected: ExpectedOutcome | ||
| let expectedWarnings: ExpectedWarnings? |
There was a problem hiding this comment.
expected is a khepri-compatible superset (Bool or { "error": ... }) plus optional description / expectedWarnings (see #6822)
Load the in-repo fixtures once and feed the decoded cases straight into the parameterized test, instead of collecting IDs and re-reading every file to find the matching case per ID. PredicateConformanceFixtureCase gains Identifiable + Sendable (for the arguments) and a CustomTestStringConvertible extension so each case still displays by id. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Asserting an exact warning count coupled the fixtures to engine internals. Match warnings by substring only (count-agnostic); an empty `contains` now asserts that no warning is emitted, preserving the "does not warn" cases. The three count-only fixtures gain the "missing variable" substring they actually emit. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Drop the khepri single-file plumbing (defaultFixtureURL, fixtureURL, the no-arg loadCases(), the env var, and the unused fixtureNotFound error). This PR only runs the in-repo PredicateFixtures/ directory; the khepri conformance loader lands with its test in the conformance PR. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
tonidero
left a comment
There was a problem hiding this comment.
I didn't check every test... But I love how easy it is now to add/modify the tests :)
I wonder if it would be worth adding a test count test as well, to make sure we don't stop running some tests... But TBH, we don't do that for other tests, so I would say not needed.
So yeah, looking amazing, thank you!
| let fixtures: [PredicateConformanceFixtureCase] | ||
| } | ||
|
|
||
| static func inRepoFixturesDirectoryURL() -> URL { |
There was a problem hiding this comment.
Hmm supernitpick but maybe could be renamed to repoFixturesDirectoryURL?
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # RevenueCat.xcodeproj/project.pbxproj
That's a great idea @tonidero! Did so in 4752b3d. We can always remove it if it gets too noisy or if it becomes a bother. But I think it's a good strategy to avoid false positives 👌 |
Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # RevenueCat.xcodeproj/project.pbxproj
Expresses the "empty-string key resolves to the whole scope and is not
missing" case as a `{"!!":{"missing":[""]}}` -> false fixture; the string
coercion the other missing fixtures use can't distinguish [] from [""].
Bumps the pinned fixture count to 237. Keeps the corpus in sync with the
purchases-android counterpart.
Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0ada6d1. Configure here.
Adds fixtures for the empty-segment dot-path splits, var default-vs-null-leaf behavior, and the non-numeric missing_some threshold (7 new cases), bumping the pinned count to 244. Also adds the var-null-path Swift test so the non-fixturizable cases match the purchases-android counterpart. Keeps the fixture corpus byte-identical across both repos. Co-authored-by: Cursor <cursoragent@cursor.com>

Checklist
purchases-androidand hybridsMotivation
Begin migrating the hand-written
RulesEngineInternaloperator unit tests into declarative JSON predicate fixtures sharing khepri's conformance format, run by one parameterized runner.Description
Package.swiftexclude.Made with Cursor
Note
Low Risk
Test-only refactor with no RulesEngineInternal production logic changes; risk is limited to CI coverage gaps if fixtures fail to load or the exclude path is wrong.
Overview
Replaces most hand-written RulesEngineInternal operator XCTest coverage with declarative JSON predicate fixtures (khepri-style conformance) driven by a shared Swift Testing suite (
PredicateFixtureTests+PredicateConformanceRunner). Per-operator cases live underPredicateFixtures/*.json(244 cases, with a pinned count guard); helpers add fixture loading,Valuedecoding for tests, and optional warning/error expectations.Removed dedicated
ArithmeticOperatorsTests,ComparisonOperatorsTests,EqualityOperatorsTests, andLogicOperatorsTests, and heavily trimmed accessor, evaluator, and string/array suites to scenarios that fixtures cannot express (e.g. array top-levelvarscope, malformed JSON parse errors, non-recursivemergestructure).Build:
Package.swiftexcludesPredicateFixturesfrom the SPM test target so JSON is read from the repo at runtime; Xcode project wires in the new helper sources.Reviewed by Cursor Bugbot for commit 7ae5c2c. Bugbot is set up for automated code reviews on this repo. Configure here.