Skip to content

test: add discount capability conformance module#62

Open
vishkaty wants to merge 1 commit into
Universal-Commerce-Protocol:mainfrom
vishkaty:feat/discount-conformance
Open

test: add discount capability conformance module#62
vishkaty wants to merge 1 commit into
Universal-Commerce-Protocol:mainfrom
vishkaty:feat/discount-conformance

Conversation

@vishkaty

Copy link
Copy Markdown
Contributor

What

Adds discount_test.py, a conformance module for the discount capability
(dev.ucp.shopping.discount). It complements the discount coverage already in
business_logic_test.py (discount flow, multiple-code accept/reject,
fixed-amount) by asserting discount MUSTs from discount.md that the suite does
not yet check:

Test Requirement
test_code_matches_case_insensitively codes are matched case-insensitively
test_discount_total_is_negative a discount's totals[] entry is negative (total.json exclusiveMaximum: 0)
test_codes_replace_previous_set a new codes[] set replaces the previous one
test_empty_codes_removes_discount an empty codes[] removes all discounts
test_allocations_sum_to_applied_amount an applied discount's allocations[] sum to its amount (a cross-field invariant the JSON schema cannot express)
test_client_applied_does_not_change_price client-supplied discounts.applied[] (response-only, ucp_request: omit) does not change the priced total

Why

These are the discount behaviours most likely to differ silently between
implementations — case-folding, the sign convention on totals[], code-set
replacement vs. accumulation, and the allocation/amount reconciliation. They are
currently unverified at the conformance level, so a merchant can regress them
and still pass. The last test also locks in that discounts are priced
server-side: a client cannot inject a cheaper order via the response-only
applied[] field.

Design

Consistent with the conformance_input-driven approach in #58: assertions are
relative (a discount reduced the total; the applied code is echoed; the
discount total is negative; an empty set clears it; allocations reconcile)
rather than tied to a specific discount value, so any conformant business passes
regardless of the discount amounts it offers. Codes are read from
conformance_input.json under test_fixtures
(valid_discount_code / second_discount_code). The module skips honestly when
no code is configured, the business does not advertise the capability, or the
server emits no allocations[].

Verification

  • All 6 tests green against the reference Flower Shop server.
  • Full suite green alongside the new module (no regression).
  • pre-commit run --all-files clean (ruff, ruff-format, prettier, codespell).

Complements business_logic_test.py by covering discount MUSTs the suite does
not assert: case-insensitive code matching (DSC-005), the negative sign of a
discount's totals[] entry (DSC-021; total.json exclusiveMaximum: 0), codes[]
replacement (DSC-003) and removal (DSC-004), the cross-field invariant that an
applied discount's allocations[] sum to its amount (DSC-022) which the JSON
schema cannot express, and that client-supplied discounts.applied[] (a
response-only field, ucp_request: omit) does not change the priced total
(DSC-027) so a client cannot inject a discount.

Server-agnostic: relative assertions driven by codes in conformance_input.json,
with honest skips when no code is configured, the business does not advertise
dev.ucp.shopping.discount, or the server emits no allocations[].
@damaz91 damaz91 added the status:needs-triage Signal that the PR is ready for human triage label Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status:needs-triage Signal that the PR is ready for human triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants