Repository navigation
Releases: rasuvaeff/property-testing-openapi
Releases · rasuvaeff/property-testing-openapi
Release list
v0.19.0
- Added. Bounded constructive generation for
prefixItems/contains
(includingminContains/maxContains),dependentRequired,
dependentSchemas, andunevaluatedProperties/unevaluatedItems(#157). - Added. Conditional schemas (
if/then/else) are generated
constructively, including boolean and nested branches. Each candidate is
checked byopenapi-contract'sSchemaCheck; unreachable branches are
omitted and a conditional with no finite value fails closed (#157). - Fixed. A member under
patternPropertiesis now generated against the
schema of the name it actually lands under. The value was compiled once for
the whole map, so every name received the schema of whichever name was drawn
first — an object whose^amember carried a boolean and whosez$member
carried a string, which the contract rejects (#157). - Changed. Requires
rasuvaeff/openapi-contract^0.16(in place of
^0.15) for the schema keywords added in 0.16:prefixItems,contains
withminContains/maxContains,dependentRequired,dependentSchemas,
unevaluatedProperties/unevaluatedItems(#157).
v0.18.0
- Changed. Requires
rasuvaeff/openapi-contract^0.15(in place of
^0.13) so downstream projects can adopt the contract's 0.14/0.15
releases (#137): 0.14 keeps a shared component as one resolution per
document (the local{$ref: '#/$defs/…'}form the generator already
unfolds since 0.16.0), 0.15 addsContract::validateWebhook()and per-leaf
body diagnostics — verdicts unchanged. No generator change was needed; the
one test expectation that moved is the formatter rendering of a body
member'sactual(now printed unless the member path looks like a
credential; wholesale[redacted]stays for a whole-body violation at
$and a cookie).
v0.17.0
- Changed. Requires
rasuvaeff/property-testing-core^1.0— the
engine's stability release, whose surface is that of 0.12.0 — in place of
^0.10 || ^0.11; the dev requirement onrasuvaeff/property-testing-testo
is^1.0likewise. Nothing in the generators or the runner changes: the
release is the constraint, so a project on the 1.0 family can install this
package beside it.rasuvaeff/openapi-contractstays at^0.13; this
package's own 1.0 waits for the contract's.
v0.16.0
- Added. A schema that refers to itself — a tree whose
childrenare
trees — is generated.rasuvaeff/openapi-contract0.13 compiles such a
schema to$defsplus a local{$ref: '#/$defs/<name>'}for every
reference back into the cycle; the generator unfolds the def three levels
below the root and ends at a leaf where the recursive member is left out —
an optional property omitted, an array that may be empty left empty, a
branch ofanyOf/oneOfskipped, a member of anallOfinlined as the
def's body. A def whose only way down is a required member that is the def
itself has no finite instance and is refused (recursive schema "…" has no finite instance), as is a def that is anallOfmember of itself; a
$refto anything but the schema's own$defsis refused by name. The
JSON body encoder follows the same references, so a nested empty object
three levels down is still written as{}. The zoo gainstree.create;
the recorded corpus grows by its 25 cases. - Changed. Requires
rasuvaeff/openapi-contract^0.13.
v0.15.2
- Fixed. Whether the
numberbranch of aoneOfadmits an integer was
judged by a copy of the contract's old floatmultipleOfrule; with
0.12.1 the contract judges on the decimals and the two disagreed on 4670
of the integers in ±100000 formultipleOf: 0.7— the generator kept
58254on theintegerbranch, the contract saw it on both, and a case
called valid was rejected. The verdict is the contract's now:
SchemaCheck::isMultipleOf()(openapi-contract 0.12.2, required as
^0.12.2). The zoo'samounts.createcarriesstep(0.7beside a wide
integer branch) and the contract's corpus is re-recorded (#132). - Fixed. A
numberschema whose bound is so wide that its decimal
multiples need more significant digits than a double holds
(|bound| × 10^decimals > 2^53) fails closed at compile time instead of
rounding onto a neighbouring decimal that is no multiple; a multiple that
divides one (1,0.5,0.25) is exempt, every double that wide being
an integer. A property pins that every generated multiple is one to the
contract (#133). - CI.
static-analysis.ymlrunscomposer rectoron every PR: 0.15.0
shipped with a rule red in a test its last commit added, and nothing
before the next PR ran rector.
v0.15.1
- Changed. Requires
rasuvaeff/openapi-contract^0.12.1, which judges
multipleOfon the decimals a message spells rather than on the parsed
doubles (openapi-contract#151). A decimal multiple is generated as the
clean decimal it means, always:64.1, never64.10000000000001. 0.15.0
emitted the float product wherever the contract's old float path demanded
it — from about64upward formultipleOf: 0.1— and 0.12.1 rejects
that product, as the specification does. The zoo'sprecise.getcarries a
decimalmultipleOfagain and the tests that pinned the agreement no
longer skip underext-bcmath.
v0.15.0
The 1.0-readiness review of 2026-09-18 (#117–#129). A minor on 0.x: the
constructor of ResponseMaterializer narrows, the OperationPropertyFailed
factories take one more argument, the RequestCaseData /
NegativeRequestCaseData psalm aliases are gone, and case-shape errors are a
type of their own.
- Changed. Requires
rasuvaeff/openapi-contract^0.12and
rasuvaeff/property-testing-core^0.10 || ^0.11(develops against
rasuvaeff/property-testing-testo^0.10 || ^0.11): the compile-time
probes catchGenerationExhaustedExceptionby name, which exists since the
core's 0.10 contract freeze, so^0.5–^0.9are no longer accepted. The
directional schema
rewrite is delegated toSchemaCheck::effective()— this package's own
copy never recursed intoadditionalProperties— and the request body and
responses arrive as the contract's typed shapes, so the guards that
re-checked them are gone. - Fixed. A numeric parameter reached the wire through
(string), which
rounds toprecision=14and put a different number there for any value
that needed more digits (846608010056.187went as846608010056.19). A
float is spelled the wayjson_encodespells it now. ThemultipleOf
generator also roundedk × mback to the decimal it meant, which from
about64upwards is one ulp away from the product the validator
computes and tolerates, so a third of the draws for0.1were rejected;
the decimal spelling is kept only where the validator agrees with it.
Underext-bcmaththe contract evaluatesmultipleOfin decimal
arithmetic and its verdict is its own — openapi-contract#151 (#117). - Fixed.
missing-requiredno longer targets a path parameter, and
negativeCoverage()no longer lists it: omitting one leaves the template
literal in the request target, which astringschema accepts, so the
negative phase failed on any/{slug}operation with
unexpectedlyValidRequest. An operation whose only required component is a
path parameter skips the category and names the reason (#118). - Fixed.
+stays%2BunderallowReserved: a raw plus in a query is
a space to the validator and to every SAPI (#119). - Fixed. A form body property with an object schema and
explode: true
is generated without undeclared members — its flatmember=valuepairs can
carry only the declared ones, and an extra landed as a top-level member of
the body. A nested object whoseminPropertiesits declared properties
cannot meet fails closed at compile time (#120). - Fixed.
oneOfover anintegerand anumberbranch was compiled as a
plain choice between disjoint branches, and half the draws matched both.
The number branch is generated without integral values, the integer branch
keeps only what the number branch's bounds and multiple refuse, and a
number branch that admits every value outside the integer branch fails
closed.1.0is an integer to JSON Schema, and is treated as one (#121). - Fixed. A multipart part declared under a JSON media type carries the
JSON encoding of its value;text/*andapplication/octet-streamparts
carry it verbatim; any other part media type fails closed instead of
sending a body the generator cannot vouch for (#122). - Fixed. Three legal documents reached a run-time
GenerationExhausted:
a header enum outside ASCII (isHeaderSafe()admits obs-text now, as RFC
9110 and the validator do), a path pattern that always carries a slash
(probed at compile time and refused by name, as is a header pattern none
of whose strings survives the wire), and an object whose twelve optionals
were drawn as independent presence choices againstmaxProperties: 1
(minProperties/maxPropertiesare met by construction: an optional past
the ceiling is left out, one needed for the floor brought in).uniqueItems
withminItemsover a bounded integer domain smaller than it fails closed
at compile time (#123). - Fixed. A header enum member with an interior space (
New York) was
refused at compile time although the validator accepts it: a scalar
header's members are refused only for whitespace at an end or a control
character, a list or object header's additionally for a comma (#129). - Added.
ContractSuite::redaction(RedactionPolicy)configures the policy
every rendering goes through:reproduce()by default (its policy
argument is optional now) and the minimal caseOperationPropertyFailed
prints, which used to be the unredacted counterexample JSON.
ContractSuite::redact(array $case): arrayapplies it to a case. The
READMEs andllms.txtclaimedCookiewas in the default redacted header
set; it is not, by design since #73, and they say so now (#124). - Added.
OpenApiPropertyTestingException, an empty marker interface
implemented by every exception of the package;InvalidCase
(\InvalidArgumentException) for a case that does not have the exported
shape — the materializer and the serializer threwUnsupportedGeneration
for it, which is a document limitation, not a caller error; a
Psr15Transportconfiguration error is aSuiteConfigurationErrorrather
than a bare\LogicException.UnsupportedGeneration::forSchema()
refusals name the operation and the parameter or body being compiled
(Unsupported OpenAPI schema generation for operation "pets.list", query parameter "limit": minLength exceeds maxLength) through
inOperation()(#127). - Changed. The case shape is declared once, on
ContractSuite
(CaseDatawithParameterMap,BodyData,PartData,MisuseData), and
imported everywhere else; theRequestCaseDataand
NegativeRequestCaseDataaliases and the inline copies are gone.
checkValid(),checkNegative(),reproduce(),redact()and
RequestMaterializer::materialize()refuse a case missing a key with
InvalidCasenaming it — a hand-written case withoutmisuseused to
raise a PHP warning and passcheckValid()(#128). - Changed.
ResponseMaterializer::__construct()no longer takes the
@internalJsonBodyEncoderandParameterSerializeras defaulted
parameters; it builds them, asRequestMaterializerdoes (#125).
CheckFailed::$resultisreadonly, assigned through the constructor by
the factories (#126).OperationPropertyFailed::forCounterExample()and
forExample()take the redacted case to print as their last argument. - Zoo:
labels.get,sparse.create,amounts.create,settings.create,
precise.get; the contract's generated corpus is re-recorded from it
(openapi-contract#152).
v0.14.1
- Fixed. Valid number schemas now keep exclusive bounds at the adjacent
IEEE-754 value, including subnormals, instead of stepping by a decimal
fraction that could cross an entire representable interval. - Fixed. Integer
multipleOfcalculations stay in the native integer
domain and fail closed at its limits; number multiples whose index cannot
fit that domain now fail closed too. - Fixed. Multipart per-part content types and encoding headers reject
invalid field names and CR/LF values before either a case or a PSR-7 request
is constructed.
v0.14.0
- Changed. Accepts
rasuvaeff/property-testing-core^0.10alongside
^0.5–^0.9, and develops againstrasuvaeff/property-testing-testo
^0.10as well. None of the 0.10 contract freeze reaches this package: it
never calledFilesystemCorpus::fromEnv(), reads noCounterExample::$skips,
names neitherGenerationExhaustednorPostconditionViolationin code
(two comments mention the former by its old name), and types every
generator asArbitraryInterface— which is exactly whatGen::*returns
from 0.10 on. The suite (866 tests) is green against core 0.10.0 and the
adapter 0.10.0. - Docs. The requirements line in both READMEs names the constraints
composer.jsonactually declares:openapi-contract^0.11(it said
^0.8 / ^0.9 / ^0.10since 0.13.0 moved on) andproperty-testing-core
^0.5–^0.10.
v0.13.1
- Fixed. A JSON body property declaring OAS 3.0
nullable: truebeside
a bound yielded no body case for any category:JsonBodyWitnesswithheld
its candidates from the check, on the reasoning that a schema admitting
nullpromises nothing about what is written over it — butnullis
admitted in addition to the declared keywords, and a string longer than
maxLengthis no more valid for it. The candidates now go to
WitnessChecklike every other property's, which already approved them.
Under OAS 3.1 nothing changes:nullableis not a keyword there, the
contract refuses the schema and the check fails closed — spell it as a
type union containingnull(#112).