what-changed v3 document testing and fixes.

sending bolts of electricity through the entire stack is throwing errors here and there, simple null values that need checking, some forgotten has functions and what not. shaking out as many bad splices as possible as we reach for the summit.
This commit is contained in:
Dave Shanley
2022-11-17 18:18:10 -05:00
parent 6382819dd0
commit a85445019d
14 changed files with 508 additions and 144 deletions

View File

@@ -193,7 +193,7 @@ func (p *PathItem) Hash() [32]byte {
f = append(f, fmt.Sprintf("%s-%s", PutLabel, low.GenerateHashString(p.Put.Value)))
}
if !p.Post.IsEmpty() {
f = append(f, fmt.Sprintf("%s-%s", PutLabel, low.GenerateHashString(p.Post.Value)))
f = append(f, fmt.Sprintf("%s-%s", PostLabel, low.GenerateHashString(p.Post.Value)))
}
if !p.Delete.IsEmpty() {
f = append(f, fmt.Sprintf("%s-%s", DeleteLabel, low.GenerateHashString(p.Delete.Value)))

View File

@@ -4,12 +4,14 @@
package v3
import (
"crypto/sha256"
"fmt"
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3"
"sort"
"strings"
)
@@ -31,6 +33,47 @@ type Components struct {
Extensions map[low.KeyReference[string]]low.ValueReference[any]
}
// Hash will return a consistent SHA256 Hash of the Encoding object
func (co *Components) Hash() [32]byte {
var f []string
generateHashForObjectMap(co.Schemas.Value, &f)
generateHashForObjectMap(co.Responses.Value, &f)
generateHashForObjectMap(co.Parameters.Value, &f)
generateHashForObjectMap(co.Examples.Value, &f)
generateHashForObjectMap(co.RequestBodies.Value, &f)
generateHashForObjectMap(co.Headers.Value, &f)
generateHashForObjectMap(co.SecuritySchemes.Value, &f)
generateHashForObjectMap(co.Links.Value, &f)
generateHashForObjectMap(co.Callbacks.Value, &f)
keys := make([]string, len(co.Extensions))
z := 0
for k := range co.Extensions {
keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(co.Extensions[k].Value))))
z++
}
sort.Strings(keys)
f = append(f, keys...)
return sha256.Sum256([]byte(strings.Join(f, "|")))
}
func generateHashForObjectMap[T any](collection map[low.KeyReference[string]]low.ValueReference[T], hash *[]string) {
if collection == nil {
return
}
l := make([]string, len(collection))
keys := make(map[string]low.ValueReference[T])
z := 0
for k := range collection {
keys[k.Value] = collection[k]
l[z] = k.Value
z++
}
sort.Strings(l)
for k := range l {
*hash = append(*hash, low.GenerateHashString(keys[l[k]].Value))
}
}
// FindExtension attempts to locate an extension with the supplied key
func (co *Components) FindExtension(ext string) *low.ValueReference[any] {
return low.FindItemInMap[any](ext, co.Extensions)

View File

@@ -49,6 +49,7 @@ const (
TitleLabel = "title"
TermsOfServiceLabel = "termsOfService"
VersionLabel = "version"
OpenAPILabel = "openapi"
HostLabel = "host"
BasePathLabel = "basePath"
LicenseLabel = "license"

View File

@@ -1,6 +1,7 @@
package v3
import (
"errors"
"github.com/pb33f/libopenapi/datamodel"
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
@@ -12,7 +13,13 @@ import (
func CreateDocument(info *datamodel.SpecInfo) (*Document, []error) {
doc := Document{Version: low.ValueReference[string]{Value: info.Version, ValueNode: info.RootNode}}
_, labelNode, versionNode := utils.FindKeyNodeFull(OpenAPILabel, info.RootNode.Content)
var version low.NodeReference[string]
if versionNode == nil {
return nil, []error{errors.New("no openapi version/tag found, cannot create document")}
}
version = low.NodeReference[string]{Value: versionNode.Value, KeyNode: labelNode, ValueNode: versionNode}
doc := Document{Version: version}
// build an index
idx := index.NewSpecIndex(info.RootNode)
@@ -31,7 +38,7 @@ func CreateDocument(info *datamodel.SpecInfo) (*Document, []error) {
_, dialectLabel, dialectNode := utils.FindKeyNodeFull(JSONSchemaDialectLabel, info.RootNode.Content)
if dialectNode != nil {
doc.JsonSchemaDialect = low.NodeReference[string]{
Value: dialectNode.Value, KeyNode: dialectLabel, ValueNode: dialectLabel}
Value: dialectNode.Value, KeyNode: dialectLabel, ValueNode: dialectNode}
}
var runExtraction = func(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex,

View File

@@ -500,7 +500,8 @@ func TestCreateDocument_CheckAdditionalProperties_Bool(t *testing.T) {
}
func TestCreateDocument_Components_Error(t *testing.T) {
yml := `components:
yml := `openapi: 3.0
components:
schemas:
bork:
properties:

View File

@@ -18,7 +18,7 @@ type Document struct {
// Version is the version of OpenAPI being used, extracted from the 'openapi: x.x.x' definition.
// This is not a standard property of the OpenAPI model, it's a convenience mechanism only.
Version low.ValueReference[string]
Version low.NodeReference[string]
// Info represents a specification Info definitions
// Provides metadata about the API. The metadata MAY be used by tooling as required.
@@ -96,6 +96,14 @@ func (d *Document) FindSecurityRequirement(name string) []low.ValueReference[str
return nil
}
func (d *Document) GetExternalDocs() *low.NodeReference[any] {
return &low.NodeReference[any]{
KeyNode: d.ExternalDocs.KeyNode,
ValueNode: d.ExternalDocs.ValueNode,
Value: d.ExternalDocs.Value,
}
}
// TODO: this is early prototype mutation/modification code, keeping it around for later.
//func (d *Document) AddTag() *base.Tag {
// t := base.NewTag()

View File

@@ -1,3 +1,4 @@
openapi: 3.0
paths:
/burgers:
post:

View File

@@ -173,12 +173,13 @@ func CheckForAddition[T any](l, r *yaml.Node, label string, changes *[]*Change,
func CheckForModification[T any](l, r *yaml.Node, label string, changes *[]*Change, breaking bool, orig, new T) {
if l != nil && l.Value != "" && r != nil && r.Value != "" && r.Value != l.Value && r.Tag == l.Tag {
CreateChange(changes, Modified, label, l, r, breaking, orig, new)
return
}
// the values may have not changed, but the tag (node type) type may have
// todo: this is currently untestable, no a single test triggers it (yet)
//if l != nil && l.Value != "" && r != nil && r.Value != "" && r.Value != l.Value && r.Tag != l.Tag {
// CreateChange(changes, Modified, label, l, r, breaking, orig, new)
//}
if l != nil && l.Value != "" && r != nil && r.Value != "" && r.Value != l.Value && r.Tag != l.Tag {
CreateChange(changes, Modified, label, l, r, breaking, orig, new)
return
}
}
// CheckMapForChanges checks a left and right low level map for any additions, subtractions or modifications to

View File

@@ -100,6 +100,14 @@ func CompareComponents(l, r any) *ComponentsChanges {
lComponents := l.(*v3.Components)
rComponents := r.(*v3.Components)
if lComponents == nil && rComponents == nil {
return nil
}
if low.AreEqual(lComponents, rComponents) {
return nil
}
doneChan := make(chan componentComparison)
comparisons := 0

View File

@@ -166,6 +166,54 @@ func CompareDocuments(l, r any) *DocumentChanges {
}
}
if reflect.TypeOf(&v3.Document{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Document{}) == reflect.TypeOf(r) {
lDoc := l.(*v3.Document)
rDoc := r.(*v3.Document)
// version
addPropertyCheck(&props, lDoc.Version.ValueNode, rDoc.Version.ValueNode,
lDoc.Version.Value, rDoc.Version.Value, &changes, v3.OpenAPILabel, true)
// schema dialect
addPropertyCheck(&props, lDoc.JsonSchemaDialect.ValueNode, rDoc.JsonSchemaDialect.ValueNode,
lDoc.JsonSchemaDialect.Value, rDoc.JsonSchemaDialect.Value, &changes, v3.JSONSchemaDialectLabel, true)
// tags
dc.TagChanges = CompareTags(lDoc.Tags.Value, rDoc.Tags.Value)
// paths
if !lDoc.Paths.IsEmpty() || !rDoc.Paths.IsEmpty() {
dc.PathsChanges = ComparePaths(lDoc.Paths.Value, rDoc.Paths.Value)
}
// external docs
compareDocumentExternalDocs(lDoc, rDoc, dc, &changes)
// info
compareDocumentInfo(&lDoc.Info, &rDoc.Info, dc, &changes)
// security
if !lDoc.Security.IsEmpty() || !rDoc.Security.IsEmpty() {
checkSecurity(lDoc.Security, rDoc.Security, &changes, dc)
}
// compare components.
if !lDoc.Components.IsEmpty() && !rDoc.Components.IsEmpty() {
if n := CompareComponents(lDoc.Components.Value, rDoc.Components.Value); n != nil {
dc.ComponentsChanges = n
}
}
// compare servers
if n := checkServers(lDoc.Servers, rDoc.Servers, &changes); n != nil {
dc.ServerChanges = n
}
// compare webhooks
CheckMapForChanges(lDoc.Webhooks.Value, rDoc.Webhooks.Value, &changes, v3.WebhooksLabel, ComparePathItemsV3)
dc.ExtensionChanges = CompareExtensions(lDoc.Extensions, rDoc.Extensions)
}
CheckProperties(props)
dc.Changes = changes
if dc.TotalChanges() <= 0 {

View File

@@ -15,6 +15,7 @@ import (
func TestCompareDocuments_Swagger_BaseProperties_Identical(t *testing.T) {
left := `swagger: 2.0
x-diet: tough
host: https://pb33f.io
basePath: /api
schemes:
@@ -46,6 +47,7 @@ produces:
func TestCompareDocuments_Swagger_BaseProperties_Modified(t *testing.T) {
left := `swagger: 2.0
x-diet: coke
host: https://pb33f.io
basePath: /api
schemes:
@@ -58,7 +60,8 @@ produces:
- application/json
- fat/belly`
right := `swagger: 2.2
right := `swagger: 2.0.1
x-diet: pepsi
host: https://quobix.com
basePath: /new-api
schemes:
@@ -71,19 +74,16 @@ produces:
- application/json
- very-fat/belly`
var lNode, rNode yaml.Node
_ = yaml.Unmarshal([]byte(left), &lNode)
_ = yaml.Unmarshal([]byte(right), &rNode)
// have to build docs fully to get access to objects
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
// create low level objects
var lDoc v2.Swagger
var rDoc v2.Swagger
_ = low.BuildModel(lNode.Content[0], &lDoc)
_ = low.BuildModel(rNode.Content[0], &rDoc)
lDoc, _ := v2.CreateDocument(siLeft)
rDoc, _ := v2.CreateDocument(siRight)
// compare.
extChanges := CompareDocuments(&lDoc, &rDoc)
assert.Equal(t, 9, extChanges.TotalChanges())
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 10, extChanges.TotalChanges())
assert.Equal(t, 6, extChanges.TotalBreakingChanges())
}
@@ -580,34 +580,176 @@ paths:
assert.Nil(t, extChanges)
}
//func TestCompareDocuments_Swagger_Components_Paths_Changed(t *testing.T) {
// left := `swagger: 2.0
//paths:
// /nice/rice:
// get:
// description: wow!
// /lovely/horse:
// put:
// description: what a lovely horse.`
//
// right := `swagger: 2.0
//paths:
// /lovely/horse:
// post:
// description: what a lovely horse.
// /nice/rice:
// get:
// description: nice rice?`
//
// // have to build docs fully to get access to objects
// siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
// siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
//
// lDoc, _ := v2.CreateDocument(siLeft)
// rDoc, _ := v2.CreateDocument(siRight)
//
// // compare.
// extChanges := CompareDocuments(lDoc, rDoc)
// assert.Equal(t, 3, extChanges.TotalChanges())
// assert.Equal(t, 1, extChanges.TotalBreakingChanges())
//}
func TestCompareDocuments_Swagger_Components_Paths_Modified(t *testing.T) {
left := `swagger: 2.0
paths:
/nice/rice:
get:
description: nice rice?
/lovely/horse:
post:
description: what a lovely horse.`
right := `swagger: 2.0
paths:
/lovely/horse:
put:
description: what a lovely horse.
/nice/rice:
get:
description: nice rice, but changed`
// have to build docs fully to get access to objects
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
lDoc, _ := v2.CreateDocument(siLeft)
rDoc, _ := v2.CreateDocument(siRight)
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 3, extChanges.TotalChanges())
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
func TestCompareDocuments_Swagger_Components_Paths_Modified_AgainForFun(t *testing.T) {
left := `swagger: 2.0
paths:
/nice/rice:
get:
description: nice rice?
/lovely/horse:
post:
description: what a lovely horse.`
right := `swagger: 2.0
paths:
/lovely/horse:
put:
description: what a lovely horse, and shoes.
/nice/rice:
post:
description: nice rice, but changed`
// have to build docs fully to get access to objects
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
lDoc, _ := v2.CreateDocument(siLeft)
rDoc, _ := v2.CreateDocument(siRight)
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 4, extChanges.TotalChanges())
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
}
func TestCompareDocuments_Swagger_Components_Tags_Identical(t *testing.T) {
left := `swagger: 2.0
tags:
- name: a tag
description: a nice tag
- name: another tag
description: this is another tag?`
right := `swagger: 2.0
tags:
- name: another tag
description: this is another tag?
- name: a tag
description: a nice tag
`
// have to build docs fully to get access to objects
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
lDoc, _ := v2.CreateDocument(siLeft)
rDoc, _ := v2.CreateDocument(siRight)
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Nil(t, extChanges)
}
func TestCompareDocuments_Swagger_Components_Tags_Modified(t *testing.T) {
left := `swagger: 2.0
tags:
- name: a tag
description: a nice tag
- name: another tag
description: this is another tag?`
right := `swagger: 2.0
tags:
- name: another tag
externalDocs:
url: https://pb33f.io
description: this is another tag, that changed
- name: a tag
description: a nice tag, modified
`
// have to build docs fully to get access to objects
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
lDoc, _ := v2.CreateDocument(siLeft)
rDoc, _ := v2.CreateDocument(siRight)
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 3, extChanges.TotalChanges())
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
func TestCompareDocuments_OpenAPI_BaseProperties_Identical(t *testing.T) {
left := `openapi: 3.1
x-diet: tough
jsonSchemaDialect: https://pb33f.io/schema`
right := left
var lNode, rNode yaml.Node
_ = yaml.Unmarshal([]byte(left), &lNode)
_ = yaml.Unmarshal([]byte(right), &rNode)
// have to build docs fully to get access to objects
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
lDoc, _ := v3.CreateDocument(siLeft)
rDoc, _ := v3.CreateDocument(siRight)
// compare.
extChanges := CompareDocuments(&lDoc, &rDoc)
assert.Nil(t, extChanges)
}
func TestCompareDocuments_OpenAPI_BaseProperties_Modified(t *testing.T) {
left := `openapi: 3.1
x-diet: tough
jsonSchemaDialect: https://pb33f.io/schema`
right := `openapi: 3.1.0
x-diet: fat
jsonSchemaDialect: https://pb33f.io/schema/changed`
var lNode, rNode yaml.Node
_ = yaml.Unmarshal([]byte(left), &lNode)
_ = yaml.Unmarshal([]byte(right), &rNode)
// have to build docs fully to get access to objects
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
lDoc, _ := v3.CreateDocument(siLeft)
rDoc, _ := v3.CreateDocument(siRight)
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 3, extChanges.TotalChanges())
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
}

View File

@@ -103,6 +103,10 @@ type opCheck struct {
changes *OperationChanges
}
func ComparePathItemsV3(l, r *v3.PathItem) *PathItemChanges {
return ComparePathItems(l, r)
}
func ComparePathItems(l, r any) *PathItemChanges {
var changes []*Change

View File

@@ -22,12 +22,14 @@ import (
// in our model, components/definitions will be checked independently for changes
// and references will be checked only for value changes (points to a different reference)
func TestCompareSchemas_PropertyModification(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
title: an OK message`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
title: an OK message Changed`
@@ -47,12 +49,14 @@ func TestCompareSchemas_PropertyModification(t *testing.T) {
}
func TestCompareSchemas_PropertyAdd(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
title: an OK message`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
title: an OK message
@@ -73,13 +77,15 @@ func TestCompareSchemas_PropertyAdd(t *testing.T) {
}
func TestCompareSchemas_PropertyRemove(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
title: an OK message
description: a thing`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
title: an OK message`
@@ -99,13 +105,15 @@ func TestCompareSchemas_PropertyRemove(t *testing.T) {
}
func TestCompareSchemas_Removed(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
title: an OK message
description: a thing`
right := `components:
right := `openapi: 3.0
components:
schemas:`
leftDoc, _ := test_BuildDoc(left, right)
@@ -121,13 +129,15 @@ func TestCompareSchemas_Removed(t *testing.T) {
}
func TestCompareSchemas_Added(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
title: an OK message
description: a thing`
right := `components:
right := `openapi: 3.0
components:
schemas:`
leftDoc, _ := test_BuildDoc(left, right)
@@ -172,14 +182,16 @@ func test_BuildDocv2(l, r string) (*v2.Swagger, *v2.Swagger) {
}
func TestCompareSchemas_RefIgnore(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
Yo:
type: int
OK:
$ref: '#/components/schemas/Yo'`
right := `components:
right := `openapi: 3.0
components:
schemas:
Yo:
type: int
@@ -197,7 +209,8 @@ func TestCompareSchemas_RefIgnore(t *testing.T) {
}
func TestCompareSchemas_RefChanged(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
Woah:
type: int
@@ -206,7 +219,8 @@ func TestCompareSchemas_RefChanged(t *testing.T) {
OK:
$ref: '#/components/schemas/Woah'`
right := `components:
right := `openapi: 3.0
components:
schemas:
Woah:
type: int
@@ -229,14 +243,16 @@ func TestCompareSchemas_RefChanged(t *testing.T) {
}
func TestCompareSchemas_RefToInline(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
Yo:
type: int
OK:
$ref: '#/components/schemas/Yo'`
right := `components:
right := `openapi: 3.0
components:
schemas:
Yo:
type: int
@@ -259,14 +275,16 @@ func TestCompareSchemas_RefToInline(t *testing.T) {
}
func TestCompareSchemas_InlineToRef(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
Yo:
type: int
OK:
$ref: '#/components/schemas/Yo'`
right := `components:
right := `openapi: 3.0
components:
schemas:
Yo:
type: int
@@ -289,14 +307,16 @@ func TestCompareSchemas_InlineToRef(t *testing.T) {
}
func TestCompareSchemas_Identical(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
Yo:
type: int
OK:
type: string`
right := `components:
right := `openapi: 3.0
components:
schemas:
Yo:
type: int
@@ -314,14 +334,16 @@ func TestCompareSchemas_Identical(t *testing.T) {
}
func TestCompareSchemas_Identical_Ref(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
Yo:
type: int
OK:
$ref: '#/components/schemas/Yo'`
right := `components:
right := `openapi: 3.0
components:
schemas:
Yo:
type: int
@@ -339,7 +361,8 @@ func TestCompareSchemas_Identical_Ref(t *testing.T) {
}
func TestCompareSchemas_RequiredAdded(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
title: an OK message
@@ -347,7 +370,8 @@ func TestCompareSchemas_RequiredAdded(t *testing.T) {
required:
- one`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
title: an OK message
@@ -371,13 +395,15 @@ func TestCompareSchemas_RequiredAdded(t *testing.T) {
}
func TestCompareSchemas_RequiredRemoved(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
required:
- one`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
required:
@@ -399,12 +425,14 @@ func TestCompareSchemas_RequiredRemoved(t *testing.T) {
}
func TestCompareSchemas_EnumAdded(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
enum: [a,b,c]`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
enum: [a,b,c,d]`
@@ -424,12 +452,14 @@ func TestCompareSchemas_EnumAdded(t *testing.T) {
}
func TestCompareSchemas_EnumRemoved(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
enum: [a,b,c]`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
enum: [a,b,c,d]`
@@ -449,14 +479,16 @@ func TestCompareSchemas_EnumRemoved(t *testing.T) {
}
func TestCompareSchemas_PropertyAdded(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
properties:
propA:
type: int`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
properties:
@@ -480,14 +512,16 @@ func TestCompareSchemas_PropertyAdded(t *testing.T) {
}
func TestCompareSchemas_PropertyRemoved(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
properties:
propA:
type: int`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
properties:
@@ -511,14 +545,16 @@ func TestCompareSchemas_PropertyRemoved(t *testing.T) {
}
func TestCompareSchemas_PropertyChanged(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
properties:
propA:
type: int`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
properties:
@@ -541,14 +577,16 @@ func TestCompareSchemas_PropertyChanged(t *testing.T) {
}
func TestCompareSchemas_PropertySwap(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
properties:
propA:
type: int`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
properties:
@@ -574,13 +612,15 @@ func TestCompareSchemas_PropertySwap(t *testing.T) {
}
func TestCompareSchemas_AnyOfModifyAndAddItem(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
anyOf:
- type: bool`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
anyOf:
@@ -605,13 +645,15 @@ func TestCompareSchemas_AnyOfModifyAndAddItem(t *testing.T) {
}
func TestCompareSchemas_AnyOfModifyAndRemoveItem(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
anyOf:
- type: bool`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
anyOf:
@@ -636,13 +678,15 @@ func TestCompareSchemas_AnyOfModifyAndRemoveItem(t *testing.T) {
}
func TestCompareSchemas_AnyOfModified(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
anyOf:
- type: bool`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
anyOf:
@@ -665,13 +709,15 @@ func TestCompareSchemas_AnyOfModified(t *testing.T) {
}
func TestCompareSchemas_OneOfModifyAndAddItem(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
oneOf:
- type: bool`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
oneOf:
@@ -696,13 +742,15 @@ func TestCompareSchemas_OneOfModifyAndAddItem(t *testing.T) {
}
func TestCompareSchemas_AllOfModifyAndAddItem(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
allOf:
- type: bool`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
allOf:
@@ -727,14 +775,16 @@ func TestCompareSchemas_AllOfModifyAndAddItem(t *testing.T) {
}
func TestCompareSchemas_ItemsModifyAndAddItem(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
type: string
items:
type: bool`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
type: string
@@ -758,14 +808,16 @@ func TestCompareSchemas_ItemsModifyAndAddItem(t *testing.T) {
}
func TestCompareSchemas_ItemsModifyAndAddItemArray(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
type: string
items:
- type: bool`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
type: string
@@ -789,14 +841,16 @@ func TestCompareSchemas_ItemsModifyAndAddItemArray(t *testing.T) {
}
func TestCompareSchemas_NotModifyAndAddItem(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
type: string
not:
type: bool`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
type: string
@@ -820,14 +874,16 @@ func TestCompareSchemas_NotModifyAndAddItem(t *testing.T) {
}
func TestCompareSchemas_DiscriminatorChange(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
type: string
discriminator:
propertyName: melody`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
type: string
@@ -851,12 +907,14 @@ func TestCompareSchemas_DiscriminatorChange(t *testing.T) {
}
func TestCompareSchemas_DiscriminatorAdd(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
type: string`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
type: string
@@ -881,12 +939,14 @@ func TestCompareSchemas_DiscriminatorAdd(t *testing.T) {
}
func TestCompareSchemas_DiscriminatorRemove(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
type: string`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
type: string
@@ -911,14 +971,16 @@ func TestCompareSchemas_DiscriminatorRemove(t *testing.T) {
}
func TestCompareSchemas_ExternalDocsChange(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
type: string
externalDocs:
url: https://pb33f.io`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
type: string
@@ -942,12 +1004,14 @@ func TestCompareSchemas_ExternalDocsChange(t *testing.T) {
}
func TestCompareSchemas_ExternalDocsAdd(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
type: string`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
type: string
@@ -972,12 +1036,14 @@ func TestCompareSchemas_ExternalDocsAdd(t *testing.T) {
}
func TestCompareSchemas_ExternalDocsRemove(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
type: string`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
type: string
@@ -1002,12 +1068,14 @@ func TestCompareSchemas_ExternalDocsRemove(t *testing.T) {
}
func TestCompareSchemas_AddExtension(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
type: string`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
type: string
@@ -1029,12 +1097,14 @@ func TestCompareSchemas_AddExtension(t *testing.T) {
}
func TestCompareSchemas_ExampleChange(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
example: sausages`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
example: yellow boat`
@@ -1056,12 +1126,14 @@ func TestCompareSchemas_ExampleChange(t *testing.T) {
}
func TestCompareSchemas_ExampleAdd(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
title: nice`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
title: nice
@@ -1083,12 +1155,14 @@ func TestCompareSchemas_ExampleAdd(t *testing.T) {
}
func TestCompareSchemas_ExampleRemove(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
title: nice`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
title: nice
@@ -1110,14 +1184,16 @@ func TestCompareSchemas_ExampleRemove(t *testing.T) {
}
func TestCompareSchemas_ExamplesChange(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
title: nice
examples:
- sausages`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
title: nice
@@ -1141,12 +1217,14 @@ func TestCompareSchemas_ExamplesChange(t *testing.T) {
}
func TestCompareSchemas_ExamplesAdd(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
title: nice`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
title: nice
@@ -1169,14 +1247,16 @@ func TestCompareSchemas_ExamplesAdd(t *testing.T) {
}
func TestCompareSchemas_ExamplesAddAndModify(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
title: nice
examples:
- sausages`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
title: nice
@@ -1203,12 +1283,14 @@ func TestCompareSchemas_ExamplesAddAndModify(t *testing.T) {
}
func TestCompareSchemas_ExamplesRemove(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
title: nice`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
title: nice
@@ -1231,14 +1313,16 @@ func TestCompareSchemas_ExamplesRemove(t *testing.T) {
}
func TestCompareSchemas_ExamplesRemoveAndModify(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
title: nice
examples:
- sausages`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
title: nice
@@ -1265,13 +1349,15 @@ func TestCompareSchemas_ExamplesRemoveAndModify(t *testing.T) {
}
func TestCompareSchemas_XMLChange(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
xml:
name: baby xml`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
xml:
@@ -1294,12 +1380,14 @@ func TestCompareSchemas_XMLChange(t *testing.T) {
}
func TestCompareSchemas_XMLAdd(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:
description: OK`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
description: OK
@@ -1322,11 +1410,13 @@ func TestCompareSchemas_XMLAdd(t *testing.T) {
}
func TestCompareSchemas_XMLRemove(t *testing.T) {
left := `components:
left := `openapi: 3.0
components:
schemas:
OK:`
right := `components:
right := `openapi: 3.0
components:
schemas:
OK:
xml:

View File

@@ -81,7 +81,7 @@ func CompareTags(l, r []low.ValueReference[*base.Tag]) *TagChanges {
RightNode: seenRight[i].Value.Description.ValueNode,
Label: v3.DescriptionLabel,
Changes: &changes,
Breaking: true,
Breaking: false,
Original: seenLeft[i].Value,
New: seenRight[i].Value,
})
@@ -90,8 +90,18 @@ func CompareTags(l, r []low.ValueReference[*base.Tag]) *TagChanges {
CheckProperties(props)
// compare external docs
tc.ExternalDocs = CompareExternalDocs(seenLeft[i].Value.ExternalDocs.Value,
seenRight[i].Value.ExternalDocs.Value)
if !seenLeft[i].Value.ExternalDocs.IsEmpty() && !seenRight[i].Value.ExternalDocs.IsEmpty() {
tc.ExternalDocs = CompareExternalDocs(seenLeft[i].Value.ExternalDocs.Value,
seenRight[i].Value.ExternalDocs.Value)
}
if seenLeft[i].Value.ExternalDocs.IsEmpty() && !seenRight[i].Value.ExternalDocs.IsEmpty() {
CreateChange(&changes, ObjectAdded, v3.ExternalDocsLabel, nil, seenRight[i].GetValueNode(),
false, nil, seenRight[i].Value.ExternalDocs.Value)
}
if !seenLeft[i].Value.ExternalDocs.IsEmpty() && seenRight[i].Value.ExternalDocs.IsEmpty() {
CreateChange(&changes, ObjectRemoved, v3.ExternalDocsLabel, seenLeft[i].GetValueNode(), nil,
false, seenLeft[i].Value.ExternalDocs.Value, nil)
}
// check extensions
tc.ExtensionChanges = CheckExtensions(seenLeft[i].GetValue(), seenRight[i].GetValue())