Represent ±Infinity in test fixtures via test-only variables#3556
Merged
Conversation
…e fixtures Adds per-operator JSON predicate fixtures (exact copies of the iOS #6885 corpus) under src/test/resources/predicate-fixtures, run by a shared parameterized runner. Deletes the migrated arithmetic/comparison/equality/ logic suites and trims the accessor/evaluator/string-array suites to the cases not expressible as predicate->boolean. Test-only change. Co-authored-by: Cursor <cursoragent@cursor.com>
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 [""]).
Removes the now-covered Kotlin test and bumps the fixture count to 237.
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), and drops the now-redundant Kotlin tests. AccessorOperatorsTest keeps only the cases that cannot be a predicate->boolean fixture (top-level array scope or a whole-object return). Fixture count is now 244. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Mirror the iOS rules-engine implementation: Kotlin some/all operators matching json-logic-js semantics, shared JSON predicate fixtures, and pinned fixture count bumped 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>
…-logic-iteration-operators
Implement variadic min/max with JS Math.min/Math.max semantics: operands coerce via Number() (toNumberOrNull), empty input yields ±∞, and NaN operands poison the result. Wire into the operator dispatcher and add byte-identical min.json/max.json fixtures from purchases-ios, bumping the pinned fixture count to 305. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Label each operator grouping in Operators.dispatch per PR review feedback. Co-authored-by: Cursor <cursoragent@cursor.com>
Move the string/array group after comparison so the Android dispatcher mirrors the iOS Operators.dispatch grouping order. 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. Fixtures kept byte-identical with iOS. 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. Fixture kept byte-identical with iOS. Co-authored-by: Cursor <cursoragent@cursor.com>
…-logic-iteration-operators
…teration-operators Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # rules-engine-internal/src/test/kotlin/com/revenuecat/purchases/rules/PredicateFixtureLoaderTest.kt
…erators' into pallares/json-logic-min-max-operators Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # rules-engine-internal/src/main/kotlin/com/revenuecat/purchases/rules/operators/Operators.kt # rules-engine-internal/src/test/kotlin/com/revenuecat/purchases/rules/PredicateFixtureLoaderTest.kt
…in-max-operators Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # rules-engine-internal/src/main/kotlin/com/revenuecat/purchases/rules/operators/Operators.kt # rules-engine-internal/src/test/kotlin/com/revenuecat/purchases/rules/PredicateFixtureLoaderTest.kt
Add a dedicated "Min and max" grouping comment so the min/max cases are not lumped under arithmetic, matching the iOS dispatcher. Co-authored-by: Cursor <cursoragent@cursor.com>
Self-documenting replacement for the {"/": [-10,0]} workaround; constants
seeded only by the conformance harness (reservedConstants), engine untouched;
NaN still uses x != x; fixtures kept byte-identical with iOS.
Co-authored-by: Cursor <cursoragent@cursor.com>
2 tasks
substr.json and missing_some.json now use the seeded "+Infinity" and "-Infinity" variables instead of division-by-zero operands. NaN cases and evaluator.json are unchanged. Fixtures are byte-identical to iOS. Co-authored-by: Cursor <cursoragent@cursor.com>
Mirror iOS predicate fixture updates: remove the redundant "comes from the test-only" clause from 7 fixture descriptions across min, max, substr, and missing_some. Fixtures kept byte-identical with iOS. Co-authored-by: Cursor <cursoragent@cursor.com>
…nfinity-fixture-vars Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # rules-engine-internal/src/test/resources/predicate-fixtures/max.json # rules-engine-internal/src/test/resources/predicate-fixtures/min.json
tonidero
approved these changes
Jun 8, 2026
rickvdl
approved these changes
Jun 8, 2026
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3556 +/- ##
=======================================
Coverage 80.15% 80.15%
=======================================
Files 371 371
Lines 15210 15210
Branches 2110 2110
=======================================
Hits 12192 12192
Misses 2168 2168
Partials 850 850 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
JSON has no
Infinityliteral, so test fixtures previously created non-finite values by dividing by zero (e.g.{"/": [-10, 0]}), which is obscure and fragile. Suggested in #3552 (comment).iOS counterpart: purchases-ios/pull/6936
Description
+Infinityand-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.{ "var": "-Infinity" }instead of a division-by-zero expression.NaNintentionally keeps thex != xself-comparison strategy, since any equality againstNaNis always false (adding a similar strategy forNaNcould lead to false positives)Note
Low Risk
Changes are confined to the predicate conformance test runner and JSON fixtures; production evaluator behavior is untouched.
Overview
Adds test-only
+Infinityand-Infinitybindings inPredicateConformanceRunner(merged into each fixture’s evaluation scope; fixturevariableswin on name clashes) so JSON conformance tests can reference non-finite floats without division-by-zero workarounds.Predicate fixtures for
max,min,missing_some, andsubstrnow use{ "var": "±Infinity" }in expectations and inputs where they previously relied on{"/": [n, 0]}. NaN cases are unchanged and still use0/0because equality againstNaNwould be unreliable with a reserved variable.Reviewed by Cursor Bugbot for commit 1186a8a. Bugbot is set up for automated code reviews on this repo. Configure here.