Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions compilers/openapi/allof_visibility_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/dexpace/morphic/compilers/openapi/internal/diag"
"github.com/dexpace/morphic/compilers/openapi/internal/openapitest"
"github.com/dexpace/morphic/ir"
)

Expand Down Expand Up @@ -109,7 +110,7 @@ func TestAllOfVisibilityMerge_ReadOnlyOnRedeclarationSurvives(t *testing.T) {

assertNoErrorDiags(t, diags)
assert.Equal(t, wantReadOnlyVisibility, got)
assert.False(t, hasDiagCode(diags, diag.ConflictingRedecl),
assert.False(t, openapitest.HasDiag(diags, diag.ConflictingRedecl),
"a redeclaration adding readOnly to an unrestricted property is not a disagreement")
}

Expand Down Expand Up @@ -150,8 +151,8 @@ func TestAllOfVisibilityMerge_DisjointRestrictionsAreInvisibleNotAConflict(t *te

assertNoErrorDiags(t, diags)
assert.Equal(t, ir.Visibility{None: true}, got)
assert.True(t, hasDiagCode(diags, diag.DisjointVisibility),
assert.True(t, openapitest.HasDiag(diags, diag.DisjointVisibility),
"an allOf that leaves a field visible nowhere is reported, not merged in silence")
assert.False(t, hasDiagCode(diags, diag.ConflictingRedecl),
assert.False(t, openapitest.HasDiag(diags, diag.ConflictingRedecl),
"disjoint readOnly/writeOnly branches intersect to an exact empty set, not an unrepresentable conflict")
}
18 changes: 4 additions & 14 deletions compilers/openapi/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

"github.com/dexpace/morphic/compilers"
"github.com/dexpace/morphic/compilers/openapi"
"github.com/dexpace/morphic/compilers/openapi/internal/openapitest"
"github.com/dexpace/morphic/internal/harness"
"github.com/dexpace/morphic/ir"
)
Expand Down Expand Up @@ -863,7 +864,7 @@ components:
assert.Equal(t, ir.ReasonValidationOnly, raw.Reason)
},
assertDiags: func(t *testing.T, diags []ir.Diagnostic) {
assert.True(t, hasDiagCode(diags, "openapi/validation-only-keyword"),
assert.True(t, openapitest.HasDiag(diags, "openapi/validation-only-keyword"),
"expected a validation-only-keyword info diagnostic")
},
}
Expand Down Expand Up @@ -894,7 +895,7 @@ components:
assert.False(t, leaked, "if/then on the declaration must not leak onto the shared primitive")
},
assertDiags: func(t *testing.T, diags []ir.Diagnostic) {
assert.True(t, hasDiagCode(diags, "openapi/validation-only-keyword"),
assert.True(t, openapitest.HasDiag(diags, "openapi/validation-only-keyword"),
"expected a validation-only-keyword info diagnostic")
},
}
Expand Down Expand Up @@ -933,7 +934,7 @@ components:
"a reference-site keyword must not attach to the referent")
},
assertDiags: func(t *testing.T, diags []ir.Diagnostic) {
assert.True(t, hasDiagCode(diags, "openapi/validation-only-keyword"),
assert.True(t, openapitest.HasDiag(diags, "openapi/validation-only-keyword"),
"expected a validation-only-keyword info diagnostic")
},
}
Expand Down Expand Up @@ -1080,17 +1081,6 @@ func primitiveNode(t *testing.T, doc *ir.Document, id ir.TypeID) ir.TypeDef {
return td
}

// hasDiagCode reports whether diags contains a diagnostic with the given
// stable code.
func hasDiagCode(diags []ir.Diagnostic, code string) bool {
for _, d := range diags {
if d.Code == code {
return true
}
}
return false
}

// declShape is one declaration shape the SiteKind axis does not name
// individually. body holds the keywords that give component S that shape, and
// value a literal legal for it, reused for both `example` and `default`.
Expand Down
14 changes: 3 additions & 11 deletions compilers/openapi/conformance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/dexpace/morphic/compilers"
"github.com/dexpace/morphic/compilers/openapi"
"github.com/dexpace/morphic/compilers/openapi/internal/diag"
"github.com/dexpace/morphic/compilers/openapi/internal/openapitest"
"github.com/dexpace/morphic/ir"
"github.com/dexpace/morphic/ir/irtest"
)
Expand Down Expand Up @@ -252,15 +253,6 @@ func namedID(name string) ir.TypeID {
return ir.TypeID("t/openapi/components/schemas/" + name)
}

// propsByWire indexes a model's properties by wire name.
func propsByWire(props []ir.Property) map[string]ir.Property {
out := make(map[string]ir.Property, len(props))
for _, p := range props {
out[p.WireName] = p
}
return out
}

// allOperations flattens every operation across a document's service groups.
func allOperations(doc *ir.Document) []ir.Operation {
var out []ir.Operation
Expand Down Expand Up @@ -930,7 +922,7 @@ func assertNullabilityFourStates(t *testing.T, doc *ir.Document, _ []ir.Diagnost
m, ok := doc.Types[namedID("S")].(*ir.Model)
require.True(t, ok)
require.Len(t, m.Properties, 4)
states := propsByWire(m.Properties)
states := openapitest.PropsByWire(m.Properties)
assert.True(t, states["reqPlain"].Required)
assert.False(t, states["reqPlain"].Type.Nullable)
assert.True(t, states["reqNull"].Required)
Expand All @@ -952,7 +944,7 @@ func assertNullable31Ref(t *testing.T, doc *ir.Document, _ []ir.Diagnostic) {
m, ok := doc.Types[namedID("Owner")].(*ir.Model)
require.True(t, ok)
require.Len(t, m.Properties, 2)
byName := propsByWire(m.Properties)
byName := openapitest.PropsByWire(m.Properties)

assert.True(t, byName["p"].Type.Nullable,
"3.1's type-array null spelling normalizes to the same IR bit at a $ref site")
Expand Down
33 changes: 17 additions & 16 deletions compilers/openapi/constraints_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import (
"github.com/stretchr/testify/require"

"github.com/dexpace/morphic/compilers/openapi/internal/diag"
"github.com/dexpace/morphic/compilers/openapi/internal/openapitest"
"github.com/dexpace/morphic/ir"
)

func TestConstraints_ExclusiveBoolean30(t *testing.T) {
t.Parallel()
spec := componentSpecVer("3.0.3", ` S:
spec := openapitest.ComponentSpecVer("3.0.3", ` S:
type: object
properties:
n:
Expand All @@ -27,7 +28,7 @@ func TestConstraints_ExclusiveBoolean30(t *testing.T) {
// to own, load suppresses that false positive, so a valid 3.0 boolean exclusive
// bound lowers cleanly with the flag set and no error diagnostic.
doc, diags := lowerSpec(t, spec)
requireNoErrorDiags(t, diags)
openapitest.RequireNoErrorDiags(t, diags)
c := propConstraints(t, doc, "S", "n")
assert.True(t, c.ExclusiveMin)
assert.True(t, c.ExclusiveMax)
Expand All @@ -37,7 +38,7 @@ func TestConstraints_ExclusiveBoolean30(t *testing.T) {

func TestConstraints_ExclusiveNumeric31(t *testing.T) {
t.Parallel()
spec := componentSpec(` S:
spec := openapitest.ComponentSpec(` S:
type: object
properties:
n:
Expand All @@ -46,7 +47,7 @@ func TestConstraints_ExclusiveNumeric31(t *testing.T) {
exclusiveMaximum: 9.5
`)
doc, diags := lowerSpec(t, spec)
requireNoErrorDiags(t, diags)
openapitest.RequireNoErrorDiags(t, diags)
c := propConstraints(t, doc, "S", "n")
assert.True(t, c.ExclusiveMin)
assert.True(t, c.ExclusiveMax)
Expand All @@ -58,7 +59,7 @@ func TestConstraints_ExclusiveNumeric31(t *testing.T) {

func TestConstraints_MalformedNumericLiterals(t *testing.T) {
t.Parallel()
spec := componentSpec(` S:
spec := openapitest.ComponentSpec(` S:
type: object
properties:
a: {type: number, minimum: .inf}
Expand All @@ -78,7 +79,7 @@ func TestConstraints_MalformedNumericLiterals(t *testing.T) {

func TestConstraints_NumericPrecisionSurvives(t *testing.T) {
t.Parallel()
spec := componentSpec(` S:
spec := openapitest.ComponentSpec(` S:
type: object
properties:
ratio:
Expand All @@ -88,7 +89,7 @@ func TestConstraints_NumericPrecisionSurvives(t *testing.T) {
multipleOf: 0.1
`)
doc, diags := lowerSpec(t, spec)
requireNoErrorDiags(t, diags)
openapitest.RequireNoErrorDiags(t, diags)
m := doc.Types[componentID("S")].(*ir.Model)
c := m.Properties[0].Constraints
require.NotNil(t, c)
Expand Down Expand Up @@ -116,11 +117,11 @@ func TestConstraints_LosslessNumericLiterals(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
spec := componentSpec(" S:\n type: object\n properties:\n n: {type: number, minimum: " + tc.literal + "}\n")
spec := openapitest.ComponentSpec(" S:\n type: object\n properties:\n n: {type: number, minimum: " + tc.literal + "}\n")
doc, diags := lowerSpec(t, spec)
// A valid number, however spelled, is accepted with no error: the
// library's float64/JSON complaint is not surfaced.
requireNoErrorDiags(t, diags)
openapitest.RequireNoErrorDiags(t, diags)
c := propConstraints(t, doc, "S", "n")
require.NotNil(t, c.Min)
assert.Equal(t, tc.want, *c.Min)
Expand All @@ -139,10 +140,10 @@ func TestConstraints_LosslessNumericLiterals(t *testing.T) {
// reddens this test — it then reports the identical error twice.
func TestConstraints_HoistedSubSchemaBadBoundSingleError(t *testing.T) {
t.Parallel()
spec := componentSpec(" Foo:\n type: object\n properties:\n bar: {type: number, minimum: hello}\n" +
spec := openapitest.ComponentSpec(" Foo:\n type: object\n properties:\n bar: {type: number, minimum: hello}\n" +
" User:\n type: object\n properties:\n b: {$ref: '#/components/schemas/Foo/properties/bar'}\n")
_, diags := lowerSpec(t, spec)
assert.Equal(t, 1, countDiagsAt(diags, diag.NumericPrecision, ir.SeverityError),
assert.Equal(t, 1, openapitest.CountDiagsAt(diags, diag.NumericPrecision, ir.SeverityError),
"one error for the shared bad bound, got: %+v", diags)
}

Expand All @@ -162,11 +163,11 @@ func TestConstraints_ExclusiveWrongDialectForm(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
spec := componentSpecVer(tc.version,
spec := openapitest.ComponentSpecVer(tc.version,
" S:\n type: object\n properties:\n n: {type: number, exclusiveMinimum: "+tc.value+"}\n")
doc, diags := lowerSpec(t, spec)
require.NotNil(t, doc)
assert.Equal(t, 1, countDiagsAt(diags, diag.ExclusiveBoundForm, ir.SeverityError),
assert.Equal(t, 1, openapitest.CountDiagsAt(diags, diag.ExclusiveBoundForm, ir.SeverityError),
"one dialect-form error, got: %+v", diags)
// The degenerate bound is dropped, not recorded.
m, ok := typeByName(doc, "S").(*ir.Model)
Expand All @@ -182,7 +183,7 @@ func TestConstraints_ExclusiveWrongDialectForm(t *testing.T) {

func TestConstraints_TypeWrongBoundYieldsSingleError(t *testing.T) {
t.Parallel()
spec := componentSpec(" S:\n type: object\n properties:\n n: {type: number, minimum: hello}\n")
spec := openapitest.ComponentSpec(" S:\n type: object\n properties:\n n: {type: number, minimum: hello}\n")
_, diags := lowerSpec(t, spec)
// Exactly one diagnostic: Morphic's error with the schema's own provenance.
// The library emits two redundant float64 type-mismatch findings on the same
Expand All @@ -195,7 +196,7 @@ func TestConstraints_TypeWrongBoundYieldsSingleError(t *testing.T) {

func TestConstraints_NonNumericMinimumErrors(t *testing.T) {
t.Parallel()
spec := componentSpec(" S:\n type: object\n properties:\n n: {type: number, minimum: hello}\n")
spec := openapitest.ComponentSpec(" S:\n type: object\n properties:\n n: {type: number, minimum: hello}\n")
doc, diags := lowerSpec(t, spec)
require.NotNil(t, doc)
// A genuinely non-numeric bound is never dropped silently: Morphic owns the
Expand Down Expand Up @@ -230,7 +231,7 @@ func propConstraints(t *testing.T, doc *ir.Document, model, wire string) *ir.Con
// numeric-precision error stamped with the component's own pointer.
func TestComponentConstraints_DiagnosticProvenance(t *testing.T) {
t.Parallel()
spec := componentSpec(" BadN: {type: number, minimum: hello}\n")
spec := openapitest.ComponentSpec(" BadN: {type: number, minimum: hello}\n")
_, diags := lowerSpec(t, spec)
var found bool
for _, d := range diags {
Expand Down
3 changes: 2 additions & 1 deletion compilers/openapi/cycles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/dexpace/morphic/compilers"
"github.com/dexpace/morphic/compilers/openapi/internal/diag"
"github.com/dexpace/morphic/compilers/openapi/internal/openapitest"
"github.com/dexpace/morphic/compilers/openapi/internal/scan"
"github.com/dexpace/morphic/ir"
)
Expand Down Expand Up @@ -265,7 +266,7 @@ func TestCompile_MergeChainPastBoundStillCompiles(t *testing.T) {
compilers.Options{})
require.NoError(t, err)
require.NotNil(t, doc, "a legal document is still compiled")
assertHasCode(t, diags, diag.CycleScanFailed, ir.SeverityWarning)
openapitest.AssertHasCode(t, diags, diag.CycleScanFailed, ir.SeverityWarning)
for _, d := range diags {
assert.NotEqual(t, ir.SeverityError, d.Severity, "no diagnostic refuses the source")
}
Expand Down
Loading
Loading