Skip to content

Migrate base RulesEngineInternal operator unit tests to JSON predicate fixtures#6885

Merged
ajpallares merged 14 commits into
mainfrom
pallares/rules-engine-json-fixtures
Jun 8, 2026
Merged

Migrate base RulesEngineInternal operator unit tests to JSON predicate fixtures#6885
ajpallares merged 14 commits into
mainfrom
pallares/rules-engine-json-fixtures

Conversation

@ajpallares

@ajpallares ajpallares commented Jun 2, 2026

Copy link
Copy Markdown
Member

Checklist

  • Unit tests
  • If applicable, create follow-up issues for purchases-android and hybrids

Motivation

Begin migrating the hand-written RulesEngineInternal operator unit tests into declarative JSON predicate fixtures sharing khepri's conformance format, run by one parameterized runner.

Description

  • Adds fixtures per-operator JSON files, covering existing operators and executed by a shared parameterized Swift Testing runner.
  • Deletes the migrated arithmetic / comparison / equality / logic unit tests; trims the accessor / evaluator / string-array suites to the cases not expressible as predicate→Bool.
  • Test-only; the sole production change is one Package.swift exclude.

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 under PredicateFixtures/*.json (244 cases, with a pinned count guard); helpers add fixture loading, Value decoding for tests, and optional warning/error expectations.

Removed dedicated ArithmeticOperatorsTests, ComparisonOperatorsTests, EqualityOperatorsTests, and LogicOperatorsTests, and heavily trimmed accessor, evaluator, and string/array suites to scenarios that fixtures cannot express (e.g. array top-level var scope, malformed JSON parse errors, non-recursive merge structure).

Build: Package.swift excludes PredicateFixtures from 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.

…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)
Comment on lines +70 to +75
let id: String
let description: String?
let predicate: Value
let variables: [String: Value]
let expected: ExpectedOutcome
let expectedWarnings: ExpectedWarnings?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected is a khepri-compatible superset (Bool or { "error": ... }) plus optional description / expectedWarnings (see #6822)

ajpallares and others added 6 commits June 2, 2026 17:16
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>
ajpallares added a commit that referenced this pull request Jun 3, 2026
@ajpallares ajpallares marked this pull request as ready for review June 5, 2026 09:23
@ajpallares ajpallares requested a review from a team as a code owner June 5, 2026 09:23

@tonidero tonidero left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm supernitpick but maybe could be renamed to repoFixturesDirectoryURL?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sure! Done in 4752b3d

Co-authored-by: Cursor <cursoragent@cursor.com>
ajpallares added a commit that referenced this pull request Jun 5, 2026
Comment thread Tests/RulesEngineInternalTests/PredicateFixtureTests.swift
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	RevenueCat.xcodeproj/project.pbxproj
@ajpallares

Copy link
Copy Markdown
Member Author

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.

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 👌

ajpallares added a commit that referenced this pull request Jun 5, 2026
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>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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.

ajpallares and others added 2 commits June 5, 2026 17:44
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>
@ajpallares ajpallares merged commit d223202 into main Jun 8, 2026
18 of 20 checks passed
@ajpallares ajpallares deleted the pallares/rules-engine-json-fixtures branch June 8, 2026 08:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants