Skip to content

Represent ±Infinity in test fixtures via test-only variables#6936

Merged
ajpallares merged 43 commits into
mainfrom
pallares/json-logic-infinity-fixture-vars
Jun 8, 2026
Merged

Represent ±Infinity in test fixtures via test-only variables#6936
ajpallares merged 43 commits into
mainfrom
pallares/json-logic-infinity-fixture-vars

Conversation

@ajpallares

@ajpallares ajpallares commented Jun 8, 2026

Copy link
Copy Markdown
Member

Motivation

JSON has no Infinity literal, so test fixtures previously created non-finite values by dividing by zero (e.g. {"/": [-10, 0]}), which is obscure and fragile. Suggested in RevenueCat/purchases-android#3552 (comment).

Android counterpart: RevenueCat/purchases-android/pull/3556

Description

  • When the tests run, the test code makes two special values available to every fixture by name — +Infinity and -Infinity, so a fixture can simply look them up. These exist only while tests run; they are never part of the real rules engine or real rule data.
  • Fixtures that need a non-finite value now read { "var": "-Infinity" } instead of a division-by-zero expression.
  • NaN intentionally keeps the x != x self-comparison strategy, since any equality against NaN is always false (adding a similar strategy for NaN could lead to false positives)

Note

Low Risk
Changes are confined to internal test helpers and JSON fixtures; production rules engine behavior is untouched.

Overview
The predicate conformance test harness now injects test-only +Infinity and -Infinity into every fixture’s variable scope (fixture-declared names override on collision), so JSON fixtures can use { "var": "±Infinity" } instead of obscure divide-by-zero expressions.

max, min, missing_some, and substr fixtures are updated to reference those variables for empty-max/min edge cases and infinite substr/missing_some thresholds. Descriptions are trimmed accordingly. NaN cases still use division-by-zero (or self-inequality) because equality against NaN would be unreliable.

Reviewed by Cursor Bugbot for commit 76cef68. Bugbot is set up for automated code reviews on this repo. Configure here.

ajpallares and others added 30 commits June 2, 2026 14:56
…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)
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>
Implements the json-logic-js some/all iteration predicates. Operator coverage
is expressed as JSON predicate fixtures (some.json / all.json) run by the
shared fixture runner introduced downstack, replacing hand-written unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit d11529c)
Implements the json-logic-js min/max operators (variadic flat list, ±∞ for
empty input, NaN propagation for non-numeric operands). Coverage is expressed
as JSON predicate fixtures (min.json / max.json) run by the shared fixture
runner, replacing hand-written unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit e73eabe)
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	RevenueCat.xcodeproj/project.pbxproj
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	RevenueCat.xcodeproj/project.pbxproj
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	RevenueCat.xcodeproj/project.pbxproj
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>
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>
…-logic-iteration-operators

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	Tests/RulesEngineInternalTests/PredicateFixtureTests.swift
…json-logic-min-max-operators

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	Tests/RulesEngineInternalTests/PredicateFixtureTests.swift
Co-authored-by: Cursor <cursoragent@cursor.com>
- Rename the object-array some/all fixtures to describe behavior instead
  of referencing the khepri oracle
- Add fixtures for literal predicates and non-boolean truthy predicate
  results
- Drop the unused opName parameter from parseIterationArgs and return an
  optional items list so a non-array source is distinguishable from an
  empty one
- Bump pinned fixture count to 271

Co-authored-by: Cursor <cursoragent@cursor.com>
Place operator docs on each op instead of duplicating at the type level;
drop "not vacuous truth" wording.

Co-authored-by: Cursor <cursoragent@cursor.com>
ajpallares and others added 10 commits June 7, 2026 12:05
Add var-fed cases (including the single-array-arg NaN gotcha), min
fail-closed and empty-list fail-closed coverage. Collapse the two-pass
NaN scan + extremum into a single reducing fold. Pinned fixture count
294 -> 301.

Co-authored-by: Cursor <cursoragent@cursor.com>
…erators' into pallares/json-logic-min-max-operators

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	Tests/RulesEngineInternalTests/PredicateFixtureTests.swift
…teration-operators

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	Tests/RulesEngineInternalTests/PredicateFixtureTests.swift
Label each operator grouping in Operators.dispatch per PR review feedback.

Co-authored-by: Cursor <cursoragent@cursor.com>
Rename the all-match fixture and add cases where only the first or only
the middle item matches, addressing PR review feedback that the existing
some coverage was order dependent.

Co-authored-by: Cursor <cursoragent@cursor.com>
khepri guards all with notEmpty, so it returns false for an empty array
like json-logic-js; drop the inaccurate claim that khepri returns true.

Co-authored-by: Cursor <cursoragent@cursor.com>
…erators' into pallares/json-logic-min-max-operators

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	Tests/RulesEngineInternalTests/PredicateFixtureTests.swift
Remove the duplicate WorkflowsCacheTests.swift PBXFileReference introduced
during a merge, and add a dedicated "Min and max" grouping comment so the
min/max cases are no longer lumped under arithmetic.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace division-by-zero workarounds ({"/": [-10,0]} / {"/": [10,0]}) with
self-documenting {"var": "±Infinity"} references. The conformance harness now
seeds reservedConstants (±Infinity) into every fixture's variable scope;
these exist only in the test harness and never touch the production engine.
NaN fixtures still use x != x.

Co-authored-by: Cursor <cursoragent@cursor.com>
ajpallares and others added 2 commits June 8, 2026 15:53
substr.json and missing_some.json ±Infinity operands now use the
seeded +Infinity/-Infinity test-only variables instead of division
by zero. NaN cases and evaluator.json are unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
Bring branch up to date after min/max squash-merge so PR #6936 shows only infinity fixture changes.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ajpallares ajpallares changed the title Use test-only ±Infinity vars in min/max empty-args fixtures Represent ±Infinity in test fixtures via test-only variables Jun 8, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
@ajpallares ajpallares marked this pull request as ready for review June 8, 2026 14:14
@ajpallares ajpallares requested a review from a team as a code owner June 8, 2026 14:14

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

Nice cleanup!

@ajpallares ajpallares enabled auto-merge (squash) June 8, 2026 14:22
@ajpallares ajpallares merged commit 2eab2a6 into main Jun 8, 2026
18 of 20 checks passed
@ajpallares ajpallares deleted the pallares/json-logic-infinity-fixture-vars branch June 8, 2026 14:29
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