mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 04:20:11 +00:00
Added support for unevaluatedProperties as Schema and bool #118
Also ran `gofmt` across the entire project. Things need cleaning up. Signed-off-by: Dave Shanley <dave@quobix.com>
This commit is contained in:
@@ -4,110 +4,110 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// CallbackChanges represents all changes made between two Callback OpenAPI objects.
|
||||
type CallbackChanges struct {
|
||||
*PropertyChanges
|
||||
ExpressionChanges map[string]*PathItemChanges `json:"expressions,omitempty" yaml:"expressions,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
*PropertyChanges
|
||||
ExpressionChanges map[string]*PathItemChanges `json:"expressions,omitempty" yaml:"expressions,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// TotalChanges returns a total count of all changes made between Callback objects
|
||||
func (c *CallbackChanges) TotalChanges() int {
|
||||
d := c.PropertyChanges.TotalChanges()
|
||||
for k := range c.ExpressionChanges {
|
||||
d += c.ExpressionChanges[k].TotalChanges()
|
||||
}
|
||||
if c.ExtensionChanges != nil {
|
||||
d += c.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return d
|
||||
d := c.PropertyChanges.TotalChanges()
|
||||
for k := range c.ExpressionChanges {
|
||||
d += c.ExpressionChanges[k].TotalChanges()
|
||||
}
|
||||
if c.ExtensionChanges != nil {
|
||||
d += c.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Callback objects
|
||||
func (c *CallbackChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, c.Changes...)
|
||||
for k := range c.ExpressionChanges {
|
||||
changes = append(changes, c.ExpressionChanges[k].GetAllChanges()...)
|
||||
}
|
||||
if c.ExtensionChanges != nil {
|
||||
changes = append(changes, c.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, c.Changes...)
|
||||
for k := range c.ExpressionChanges {
|
||||
changes = append(changes, c.ExpressionChanges[k].GetAllChanges()...)
|
||||
}
|
||||
if c.ExtensionChanges != nil {
|
||||
changes = append(changes, c.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns a total count of all changes made between Callback objects
|
||||
func (c *CallbackChanges) TotalBreakingChanges() int {
|
||||
d := c.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range c.ExpressionChanges {
|
||||
d += c.ExpressionChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
if c.ExtensionChanges != nil {
|
||||
d += c.ExtensionChanges.TotalBreakingChanges()
|
||||
}
|
||||
return d
|
||||
d := c.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range c.ExpressionChanges {
|
||||
d += c.ExpressionChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
if c.ExtensionChanges != nil {
|
||||
d += c.ExtensionChanges.TotalBreakingChanges()
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// CompareCallback will compare two Callback objects and return a pointer to CallbackChanges with all the things
|
||||
// that have changed between them.
|
||||
func CompareCallback(l, r *v3.Callback) *CallbackChanges {
|
||||
|
||||
cc := new(CallbackChanges)
|
||||
var changes []*Change
|
||||
cc := new(CallbackChanges)
|
||||
var changes []*Change
|
||||
|
||||
lHashes := make(map[string]string)
|
||||
rHashes := make(map[string]string)
|
||||
lHashes := make(map[string]string)
|
||||
rHashes := make(map[string]string)
|
||||
|
||||
lValues := make(map[string]low.ValueReference[*v3.PathItem])
|
||||
rValues := make(map[string]low.ValueReference[*v3.PathItem])
|
||||
lValues := make(map[string]low.ValueReference[*v3.PathItem])
|
||||
rValues := make(map[string]low.ValueReference[*v3.PathItem])
|
||||
|
||||
for k := range l.Expression.Value {
|
||||
lHashes[k.Value] = low.GenerateHashString(l.Expression.Value[k].Value)
|
||||
lValues[k.Value] = l.Expression.Value[k]
|
||||
}
|
||||
for k := range l.Expression.Value {
|
||||
lHashes[k.Value] = low.GenerateHashString(l.Expression.Value[k].Value)
|
||||
lValues[k.Value] = l.Expression.Value[k]
|
||||
}
|
||||
|
||||
for k := range r.Expression.Value {
|
||||
rHashes[k.Value] = low.GenerateHashString(r.Expression.Value[k].Value)
|
||||
rValues[k.Value] = r.Expression.Value[k]
|
||||
}
|
||||
for k := range r.Expression.Value {
|
||||
rHashes[k.Value] = low.GenerateHashString(r.Expression.Value[k].Value)
|
||||
rValues[k.Value] = r.Expression.Value[k]
|
||||
}
|
||||
|
||||
expChanges := make(map[string]*PathItemChanges)
|
||||
expChanges := make(map[string]*PathItemChanges)
|
||||
|
||||
// check left path item hashes
|
||||
for k := range lHashes {
|
||||
rhash := rHashes[k]
|
||||
if rhash == "" {
|
||||
CreateChange(&changes, ObjectRemoved, k,
|
||||
lValues[k].GetValueNode(), nil, true,
|
||||
lValues[k].GetValue(), nil)
|
||||
continue
|
||||
}
|
||||
if lHashes[k] == rHashes[k] {
|
||||
continue
|
||||
}
|
||||
// run comparison.
|
||||
expChanges[k] = ComparePathItems(lValues[k].Value, rValues[k].Value)
|
||||
}
|
||||
// check left path item hashes
|
||||
for k := range lHashes {
|
||||
rhash := rHashes[k]
|
||||
if rhash == "" {
|
||||
CreateChange(&changes, ObjectRemoved, k,
|
||||
lValues[k].GetValueNode(), nil, true,
|
||||
lValues[k].GetValue(), nil)
|
||||
continue
|
||||
}
|
||||
if lHashes[k] == rHashes[k] {
|
||||
continue
|
||||
}
|
||||
// run comparison.
|
||||
expChanges[k] = ComparePathItems(lValues[k].Value, rValues[k].Value)
|
||||
}
|
||||
|
||||
//check right path item hashes
|
||||
for k := range rHashes {
|
||||
lhash := lHashes[k]
|
||||
if lhash == "" {
|
||||
CreateChange(&changes, ObjectAdded, k,
|
||||
nil, rValues[k].GetValueNode(), false,
|
||||
nil, rValues[k].GetValue())
|
||||
continue
|
||||
}
|
||||
}
|
||||
cc.ExpressionChanges = expChanges
|
||||
cc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
cc.PropertyChanges = NewPropertyChanges(changes)
|
||||
if cc.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return cc
|
||||
//check right path item hashes
|
||||
for k := range rHashes {
|
||||
lhash := lHashes[k]
|
||||
if lhash == "" {
|
||||
CreateChange(&changes, ObjectAdded, k,
|
||||
nil, rValues[k].GetValueNode(), false,
|
||||
nil, rValues[k].GetValue())
|
||||
continue
|
||||
}
|
||||
}
|
||||
cc.ExpressionChanges = expChanges
|
||||
cc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
cc.PropertyChanges = NewPropertyChanges(changes)
|
||||
if cc.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return cc
|
||||
}
|
||||
|
||||
@@ -4,42 +4,42 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"gopkg.in/yaml.v3"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Definitions of the possible changes between two items
|
||||
const (
|
||||
|
||||
// Modified means that was a modification of a value was made
|
||||
Modified = iota + 1
|
||||
// Modified means that was a modification of a value was made
|
||||
Modified = iota + 1
|
||||
|
||||
// PropertyAdded means that a new property to an object was added
|
||||
PropertyAdded
|
||||
// PropertyAdded means that a new property to an object was added
|
||||
PropertyAdded
|
||||
|
||||
// ObjectAdded means that a new object was added to a parent object
|
||||
ObjectAdded
|
||||
// ObjectAdded means that a new object was added to a parent object
|
||||
ObjectAdded
|
||||
|
||||
// ObjectRemoved means that an object was removed from a parent object
|
||||
ObjectRemoved
|
||||
// ObjectRemoved means that an object was removed from a parent object
|
||||
ObjectRemoved
|
||||
|
||||
// PropertyRemoved means that a property of an object was removed
|
||||
PropertyRemoved
|
||||
// PropertyRemoved means that a property of an object was removed
|
||||
PropertyRemoved
|
||||
)
|
||||
|
||||
// WhatChanged is a summary object that contains a high level summary of everything changed.
|
||||
type WhatChanged struct {
|
||||
Added int `json:"added,omitempty" yaml:"added,omitempty"`
|
||||
Removed int `json:"removed,omitempty" yaml:"removed,omitempty"`
|
||||
Modified int `json:"modified,omitempty" yaml:"modified,omitempty"`
|
||||
TotalChanges int `json:"total,omitempty" yaml:"total,omitempty"`
|
||||
Added int `json:"added,omitempty" yaml:"added,omitempty"`
|
||||
Removed int `json:"removed,omitempty" yaml:"removed,omitempty"`
|
||||
Modified int `json:"modified,omitempty" yaml:"modified,omitempty"`
|
||||
TotalChanges int `json:"total,omitempty" yaml:"total,omitempty"`
|
||||
}
|
||||
|
||||
// ChangeContext holds a reference to the line and column positions of original and new change.
|
||||
type ChangeContext struct {
|
||||
OriginalLine *int `json:"originalLine,omitempty" yaml:"originalLine,omitempty"`
|
||||
OriginalColumn *int `json:"originalColumn,omitempty" yaml:"originalColumn,omitempty"`
|
||||
NewLine *int `json:"newLine,omitempty" yaml:"newLine,omitempty"`
|
||||
NewColumn *int `json:"newColumn,omitempty" yaml:"newColumn,omitempty"`
|
||||
OriginalLine *int `json:"originalLine,omitempty" yaml:"originalLine,omitempty"`
|
||||
OriginalColumn *int `json:"originalColumn,omitempty" yaml:"originalColumn,omitempty"`
|
||||
NewLine *int `json:"newLine,omitempty" yaml:"newLine,omitempty"`
|
||||
NewColumn *int `json:"newColumn,omitempty" yaml:"newColumn,omitempty"`
|
||||
}
|
||||
|
||||
// HasChanged determines if the line and column numbers of the original and new values have changed.
|
||||
@@ -47,93 +47,93 @@ type ChangeContext struct {
|
||||
// It's worth noting that there is no guarantee to the positions of anything in either left or right, so
|
||||
// considering these values as 'changes' is going to add a considerable amount of noise to results.
|
||||
func (c *ChangeContext) HasChanged() bool {
|
||||
if c.NewLine != nil && c.OriginalLine != nil && *c.NewLine != *c.OriginalLine {
|
||||
return true
|
||||
}
|
||||
//if c.NewColumn != nil && c.OriginalColumn != nil && *c.NewColumn != *c.OriginalColumn {
|
||||
// return true
|
||||
//}
|
||||
if (c.NewLine == nil && c.OriginalLine != nil) || (c.NewLine != nil && c.OriginalLine == nil) {
|
||||
return true
|
||||
}
|
||||
//if (c.NewColumn == nil && c.OriginalColumn != nil) || (c.NewColumn != nil && c.OriginalColumn == nil) {
|
||||
// return true
|
||||
//}
|
||||
return false
|
||||
if c.NewLine != nil && c.OriginalLine != nil && *c.NewLine != *c.OriginalLine {
|
||||
return true
|
||||
}
|
||||
//if c.NewColumn != nil && c.OriginalColumn != nil && *c.NewColumn != *c.OriginalColumn {
|
||||
// return true
|
||||
//}
|
||||
if (c.NewLine == nil && c.OriginalLine != nil) || (c.NewLine != nil && c.OriginalLine == nil) {
|
||||
return true
|
||||
}
|
||||
//if (c.NewColumn == nil && c.OriginalColumn != nil) || (c.NewColumn != nil && c.OriginalColumn == nil) {
|
||||
// return true
|
||||
//}
|
||||
return false
|
||||
}
|
||||
|
||||
// Change represents a change between two different elements inside an OpenAPI specification.
|
||||
type Change struct {
|
||||
|
||||
// Context represents the lines and column numbers of the original and new values
|
||||
// It's worth noting that these values may frequently be different and are not used to calculate
|
||||
// a change. If the positions change, but values do not, then no change is recorded.
|
||||
Context *ChangeContext `json:"context,omitempty" yaml:"context,omitempty"`
|
||||
// Context represents the lines and column numbers of the original and new values
|
||||
// It's worth noting that these values may frequently be different and are not used to calculate
|
||||
// a change. If the positions change, but values do not, then no change is recorded.
|
||||
Context *ChangeContext `json:"context,omitempty" yaml:"context,omitempty"`
|
||||
|
||||
// ChangeType represents the type of change that occurred. stored as an integer, defined by constants above.
|
||||
ChangeType int `json:"change,omitempty" yaml:"change,omitempty"`
|
||||
// ChangeType represents the type of change that occurred. stored as an integer, defined by constants above.
|
||||
ChangeType int `json:"change,omitempty" yaml:"change,omitempty"`
|
||||
|
||||
// Property is the property name key being changed.
|
||||
Property string `json:"property,omitempty" yaml:"property,omitempty"`
|
||||
// Property is the property name key being changed.
|
||||
Property string `json:"property,omitempty" yaml:"property,omitempty"`
|
||||
|
||||
// Original is the original value represented as a string.
|
||||
Original string `json:"original,omitempty" yaml:"original,omitempty"`
|
||||
// Original is the original value represented as a string.
|
||||
Original string `json:"original,omitempty" yaml:"original,omitempty"`
|
||||
|
||||
// New is the new value represented as a string.
|
||||
New string `json:"new,omitempty" yaml:"new,omitempty"`
|
||||
// New is the new value represented as a string.
|
||||
New string `json:"new,omitempty" yaml:"new,omitempty"`
|
||||
|
||||
// Breaking determines if the change is a breaking one or not.
|
||||
Breaking bool `json:"breaking" yaml:"breaking"`
|
||||
// Breaking determines if the change is a breaking one or not.
|
||||
Breaking bool `json:"breaking" yaml:"breaking"`
|
||||
|
||||
// OriginalObject represents the original object that was changed.
|
||||
OriginalObject any `json:"-" yaml:"-"`
|
||||
// OriginalObject represents the original object that was changed.
|
||||
OriginalObject any `json:"-" yaml:"-"`
|
||||
|
||||
// NewObject represents the new object that has been modified.
|
||||
NewObject any `json:"-" yaml:"-"`
|
||||
// NewObject represents the new object that has been modified.
|
||||
NewObject any `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
// PropertyChanges holds a slice of Change pointers
|
||||
type PropertyChanges struct {
|
||||
//Total *int `json:"total,omitempty" yaml:"total,omitempty"`
|
||||
//Breaking *int `json:"breaking,omitempty" yaml:"breaking,omitempty"`
|
||||
Changes []*Change `json:"changes,omitempty" yaml:"changes,omitempty"`
|
||||
//Total *int `json:"total,omitempty" yaml:"total,omitempty"`
|
||||
//Breaking *int `json:"breaking,omitempty" yaml:"breaking,omitempty"`
|
||||
Changes []*Change `json:"changes,omitempty" yaml:"changes,omitempty"`
|
||||
}
|
||||
|
||||
// TotalChanges returns the total number of property changes made.
|
||||
func (p PropertyChanges) TotalChanges() int {
|
||||
return len(p.Changes)
|
||||
return len(p.Changes)
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the total number of property breaking changes made.
|
||||
func (p PropertyChanges) TotalBreakingChanges() int {
|
||||
return CountBreakingChanges(p.Changes)
|
||||
return CountBreakingChanges(p.Changes)
|
||||
}
|
||||
|
||||
func NewPropertyChanges(changes []*Change) *PropertyChanges {
|
||||
return &PropertyChanges{Changes: changes}
|
||||
return &PropertyChanges{Changes: changes}
|
||||
}
|
||||
|
||||
// PropertyCheck is used by functions to check the state of left and right values.
|
||||
type PropertyCheck struct {
|
||||
|
||||
// Original is the property we're checking on the left
|
||||
Original any
|
||||
// Original is the property we're checking on the left
|
||||
Original any
|
||||
|
||||
// New is s the property we're checking on the right
|
||||
New any
|
||||
// New is s the property we're checking on the right
|
||||
New any
|
||||
|
||||
// Label is the identifier we're looking for on the left and right hand sides
|
||||
Label string
|
||||
// Label is the identifier we're looking for on the left and right hand sides
|
||||
Label string
|
||||
|
||||
// LeftNode is the yaml.Node pointer that holds the original node structure of the value
|
||||
LeftNode *yaml.Node
|
||||
// LeftNode is the yaml.Node pointer that holds the original node structure of the value
|
||||
LeftNode *yaml.Node
|
||||
|
||||
// RightNode is the yaml.Node pointer that holds the new node structure of the value
|
||||
RightNode *yaml.Node
|
||||
// RightNode is the yaml.Node pointer that holds the new node structure of the value
|
||||
RightNode *yaml.Node
|
||||
|
||||
// Breaking determines if the check is a breaking change (modifications or removals etc.)
|
||||
Breaking bool
|
||||
// Breaking determines if the check is a breaking change (modifications or removals etc.)
|
||||
Breaking bool
|
||||
|
||||
// Changes represents a pointer to the slice to contain all changes found.
|
||||
Changes *[]*Change
|
||||
// Changes represents a pointer to the slice to contain all changes found.
|
||||
Changes *[]*Change
|
||||
}
|
||||
|
||||
@@ -4,28 +4,28 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// ContactChanges Represent changes to a Contact object that is a child of Info, part of an OpenAPI document.
|
||||
type ContactChanges struct {
|
||||
*PropertyChanges
|
||||
*PropertyChanges
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Callback objects
|
||||
func (c *ContactChanges) GetAllChanges() []*Change {
|
||||
return c.Changes
|
||||
return c.Changes
|
||||
}
|
||||
|
||||
// TotalChanges represents the total number of changes that have occurred to a Contact object
|
||||
func (c *ContactChanges) TotalChanges() int {
|
||||
return c.PropertyChanges.TotalChanges()
|
||||
return c.PropertyChanges.TotalChanges()
|
||||
}
|
||||
|
||||
// TotalBreakingChanges always returns 0 for Contact objects, they are non-binding.
|
||||
func (c *ContactChanges) TotalBreakingChanges() int {
|
||||
return 0
|
||||
return 0
|
||||
}
|
||||
|
||||
// CompareContact will check a left (original) and right (new) Contact object for any changes. If there
|
||||
@@ -33,49 +33,49 @@ func (c *ContactChanges) TotalBreakingChanges() int {
|
||||
// returns nil.
|
||||
func CompareContact(l, r *base.Contact) *ContactChanges {
|
||||
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
|
||||
// check URL
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.URL.ValueNode,
|
||||
RightNode: r.URL.ValueNode,
|
||||
Label: v3.URLLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// check URL
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.URL.ValueNode,
|
||||
RightNode: r.URL.ValueNode,
|
||||
Label: v3.URLLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// check name
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Name.ValueNode,
|
||||
RightNode: r.Name.ValueNode,
|
||||
Label: v3.NameLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// check name
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Name.ValueNode,
|
||||
RightNode: r.Name.ValueNode,
|
||||
Label: v3.NameLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// check email
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Email.ValueNode,
|
||||
RightNode: r.Email.ValueNode,
|
||||
Label: v3.EmailLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// check email
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Email.ValueNode,
|
||||
RightNode: r.Email.ValueNode,
|
||||
Label: v3.EmailLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// check everything.
|
||||
CheckProperties(props)
|
||||
// check everything.
|
||||
CheckProperties(props)
|
||||
|
||||
dc := new(ContactChanges)
|
||||
dc.PropertyChanges = NewPropertyChanges(changes)
|
||||
if dc.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return dc
|
||||
dc := new(ContactChanges)
|
||||
dc.PropertyChanges = NewPropertyChanges(changes)
|
||||
if dc.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return dc
|
||||
}
|
||||
|
||||
@@ -4,93 +4,93 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// DiscriminatorChanges represents changes made to a Discriminator OpenAPI object
|
||||
type DiscriminatorChanges struct {
|
||||
*PropertyChanges
|
||||
MappingChanges []*Change `json:"mappings,omitempty" yaml:"mappings,omitempty"`
|
||||
*PropertyChanges
|
||||
MappingChanges []*Change `json:"mappings,omitempty" yaml:"mappings,omitempty"`
|
||||
}
|
||||
|
||||
// TotalChanges returns a count of everything changed within the Discriminator object
|
||||
func (d *DiscriminatorChanges) TotalChanges() int {
|
||||
l := 0
|
||||
if k := d.PropertyChanges.TotalChanges(); k > 0 {
|
||||
l += k
|
||||
}
|
||||
if k := len(d.MappingChanges); k > 0 {
|
||||
l += k
|
||||
}
|
||||
return l
|
||||
l := 0
|
||||
if k := d.PropertyChanges.TotalChanges(); k > 0 {
|
||||
l += k
|
||||
}
|
||||
if k := len(d.MappingChanges); k > 0 {
|
||||
l += k
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Callback objects
|
||||
func (c *DiscriminatorChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, c.Changes...)
|
||||
if c.MappingChanges != nil {
|
||||
changes = append(changes, c.MappingChanges...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, c.Changes...)
|
||||
if c.MappingChanges != nil {
|
||||
changes = append(changes, c.MappingChanges...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the number of breaking changes made by the Discriminator
|
||||
func (d *DiscriminatorChanges) TotalBreakingChanges() int {
|
||||
return d.PropertyChanges.TotalBreakingChanges() + CountBreakingChanges(d.MappingChanges)
|
||||
return d.PropertyChanges.TotalBreakingChanges() + CountBreakingChanges(d.MappingChanges)
|
||||
}
|
||||
|
||||
// CompareDiscriminator will check a left (original) and right (new) Discriminator object for changes
|
||||
// and will return a pointer to DiscriminatorChanges
|
||||
func CompareDiscriminator(l, r *base.Discriminator) *DiscriminatorChanges {
|
||||
dc := new(DiscriminatorChanges)
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var mappingChanges []*Change
|
||||
dc := new(DiscriminatorChanges)
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var mappingChanges []*Change
|
||||
|
||||
// Name (breaking change)
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.PropertyName.ValueNode,
|
||||
RightNode: r.PropertyName.ValueNode,
|
||||
Label: v3.PropertyNameLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// Name (breaking change)
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.PropertyName.ValueNode,
|
||||
RightNode: r.PropertyName.ValueNode,
|
||||
Label: v3.PropertyNameLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// check properties
|
||||
CheckProperties(props)
|
||||
// check properties
|
||||
CheckProperties(props)
|
||||
|
||||
// flatten maps
|
||||
lMap := FlattenLowLevelMap[string](l.Mapping.Value)
|
||||
rMap := FlattenLowLevelMap[string](r.Mapping.Value)
|
||||
// flatten maps
|
||||
lMap := FlattenLowLevelMap[string](l.Mapping.Value)
|
||||
rMap := FlattenLowLevelMap[string](r.Mapping.Value)
|
||||
|
||||
// check for removals, modifications and moves
|
||||
for i := range lMap {
|
||||
CheckForObjectAdditionOrRemoval[string](lMap, rMap, i, &mappingChanges, false, true)
|
||||
// if the existing tag exists, let's check it.
|
||||
if rMap[i] != nil {
|
||||
if lMap[i].Value != rMap[i].Value {
|
||||
CreateChange(&mappingChanges, Modified, i, lMap[i].GetValueNode(),
|
||||
rMap[i].GetValueNode(), true, lMap[i].GetValue(), rMap[i].GetValue())
|
||||
}
|
||||
}
|
||||
}
|
||||
// check for removals, modifications and moves
|
||||
for i := range lMap {
|
||||
CheckForObjectAdditionOrRemoval[string](lMap, rMap, i, &mappingChanges, false, true)
|
||||
// if the existing tag exists, let's check it.
|
||||
if rMap[i] != nil {
|
||||
if lMap[i].Value != rMap[i].Value {
|
||||
CreateChange(&mappingChanges, Modified, i, lMap[i].GetValueNode(),
|
||||
rMap[i].GetValueNode(), true, lMap[i].GetValue(), rMap[i].GetValue())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := range rMap {
|
||||
if lMap[i] == nil {
|
||||
CreateChange(&mappingChanges, ObjectAdded, i, nil,
|
||||
rMap[i].GetValueNode(), false, nil, rMap[i].GetValue())
|
||||
}
|
||||
}
|
||||
for i := range rMap {
|
||||
if lMap[i] == nil {
|
||||
CreateChange(&mappingChanges, ObjectAdded, i, nil,
|
||||
rMap[i].GetValueNode(), false, nil, rMap[i].GetValue())
|
||||
}
|
||||
}
|
||||
|
||||
dc.PropertyChanges = NewPropertyChanges(changes)
|
||||
dc.MappingChanges = mappingChanges
|
||||
if dc.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return dc
|
||||
dc.PropertyChanges = NewPropertyChanges(changes)
|
||||
dc.MappingChanges = mappingChanges
|
||||
if dc.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return dc
|
||||
|
||||
}
|
||||
|
||||
@@ -4,96 +4,96 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// EncodingChanges represent all the changes made to an Encoding object
|
||||
type EncodingChanges struct {
|
||||
*PropertyChanges
|
||||
HeaderChanges map[string]*HeaderChanges `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
*PropertyChanges
|
||||
HeaderChanges map[string]*HeaderChanges `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Encoding objects
|
||||
func (e *EncodingChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, e.Changes...)
|
||||
for k := range e.HeaderChanges {
|
||||
changes = append(changes, e.HeaderChanges[k].GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, e.Changes...)
|
||||
for k := range e.HeaderChanges {
|
||||
changes = append(changes, e.HeaderChanges[k].GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the total number of changes made between two Encoding objects
|
||||
func (e *EncodingChanges) TotalChanges() int {
|
||||
c := e.PropertyChanges.TotalChanges()
|
||||
if e.HeaderChanges != nil {
|
||||
for i := range e.HeaderChanges {
|
||||
c += e.HeaderChanges[i].TotalChanges()
|
||||
}
|
||||
}
|
||||
return c
|
||||
c := e.PropertyChanges.TotalChanges()
|
||||
if e.HeaderChanges != nil {
|
||||
for i := range e.HeaderChanges {
|
||||
c += e.HeaderChanges[i].TotalChanges()
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the number of changes made between two Encoding objects that were breaking.
|
||||
func (e *EncodingChanges) TotalBreakingChanges() int {
|
||||
c := e.PropertyChanges.TotalBreakingChanges()
|
||||
if e.HeaderChanges != nil {
|
||||
for i := range e.HeaderChanges {
|
||||
c += e.HeaderChanges[i].TotalBreakingChanges()
|
||||
}
|
||||
}
|
||||
return c
|
||||
c := e.PropertyChanges.TotalBreakingChanges()
|
||||
if e.HeaderChanges != nil {
|
||||
for i := range e.HeaderChanges {
|
||||
c += e.HeaderChanges[i].TotalBreakingChanges()
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CompareEncoding returns a pointer to *EncodingChanges that contain all changes made between a left and right
|
||||
// set of Encoding objects.
|
||||
func CompareEncoding(l, r *v3.Encoding) *EncodingChanges {
|
||||
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
|
||||
// ContentType
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.ContentType.ValueNode,
|
||||
RightNode: r.ContentType.ValueNode,
|
||||
Label: v3.ContentTypeLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// ContentType
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.ContentType.ValueNode,
|
||||
RightNode: r.ContentType.ValueNode,
|
||||
Label: v3.ContentTypeLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// Explode
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Explode.ValueNode,
|
||||
RightNode: r.Explode.ValueNode,
|
||||
Label: v3.ExplodeLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// Explode
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Explode.ValueNode,
|
||||
RightNode: r.Explode.ValueNode,
|
||||
Label: v3.ExplodeLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// AllowReserved
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.AllowReserved.ValueNode,
|
||||
RightNode: r.AllowReserved.ValueNode,
|
||||
Label: v3.AllowReservedLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// AllowReserved
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.AllowReserved.ValueNode,
|
||||
RightNode: r.AllowReserved.ValueNode,
|
||||
Label: v3.AllowReservedLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// check everything.
|
||||
CheckProperties(props)
|
||||
ec := new(EncodingChanges)
|
||||
// check everything.
|
||||
CheckProperties(props)
|
||||
ec := new(EncodingChanges)
|
||||
|
||||
// headers
|
||||
ec.HeaderChanges = CheckMapForChanges(l.Headers.Value, r.Headers.Value, &changes, v3.HeadersLabel, CompareHeadersV3)
|
||||
ec.PropertyChanges = NewPropertyChanges(changes)
|
||||
if ec.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return ec
|
||||
// headers
|
||||
ec.HeaderChanges = CheckMapForChanges(l.Headers.Value, r.Headers.Value, &changes, v3.HeadersLabel, CompareHeadersV3)
|
||||
ec.PropertyChanges = NewPropertyChanges(changes)
|
||||
if ec.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return ec
|
||||
}
|
||||
|
||||
@@ -4,83 +4,83 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
)
|
||||
|
||||
// ExamplesChanges represents changes made between Swagger Examples objects (Not OpenAPI 3).
|
||||
type ExamplesChanges struct {
|
||||
*PropertyChanges
|
||||
*PropertyChanges
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Examples objects
|
||||
func (a *ExamplesChanges) GetAllChanges() []*Change {
|
||||
return a.Changes
|
||||
return a.Changes
|
||||
}
|
||||
|
||||
// TotalChanges represents the total number of changes made between Example instances.
|
||||
func (a *ExamplesChanges) TotalChanges() int {
|
||||
return a.PropertyChanges.TotalChanges()
|
||||
return a.PropertyChanges.TotalChanges()
|
||||
}
|
||||
|
||||
// TotalBreakingChanges will always return 0. Examples cannot break a contract.
|
||||
func (a *ExamplesChanges) TotalBreakingChanges() int {
|
||||
return 0 // not supported.
|
||||
return 0 // not supported.
|
||||
}
|
||||
|
||||
// CompareExamplesV2 compares two Swagger Examples objects, returning a pointer to
|
||||
//ExamplesChanges if anything was found.
|
||||
// ExamplesChanges if anything was found.
|
||||
func CompareExamplesV2(l, r *v2.Examples) *ExamplesChanges {
|
||||
|
||||
lHashes := make(map[string]string)
|
||||
rHashes := make(map[string]string)
|
||||
lValues := make(map[string]low.ValueReference[any])
|
||||
rValues := make(map[string]low.ValueReference[any])
|
||||
lHashes := make(map[string]string)
|
||||
rHashes := make(map[string]string)
|
||||
lValues := make(map[string]low.ValueReference[any])
|
||||
rValues := make(map[string]low.ValueReference[any])
|
||||
|
||||
for k := range l.Values {
|
||||
lHashes[k.Value] = low.GenerateHashString(l.Values[k].Value)
|
||||
lValues[k.Value] = l.Values[k]
|
||||
}
|
||||
for k := range l.Values {
|
||||
lHashes[k.Value] = low.GenerateHashString(l.Values[k].Value)
|
||||
lValues[k.Value] = l.Values[k]
|
||||
}
|
||||
|
||||
for k := range r.Values {
|
||||
rHashes[k.Value] = low.GenerateHashString(r.Values[k].Value)
|
||||
rValues[k.Value] = r.Values[k]
|
||||
}
|
||||
var changes []*Change
|
||||
for k := range r.Values {
|
||||
rHashes[k.Value] = low.GenerateHashString(r.Values[k].Value)
|
||||
rValues[k.Value] = r.Values[k]
|
||||
}
|
||||
var changes []*Change
|
||||
|
||||
// check left example hashes
|
||||
for k := range lHashes {
|
||||
rhash := rHashes[k]
|
||||
if rhash == "" {
|
||||
CreateChange(&changes, ObjectRemoved, k,
|
||||
lValues[k].GetValueNode(), nil, false,
|
||||
lValues[k].GetValue(), nil)
|
||||
continue
|
||||
}
|
||||
if lHashes[k] == rHashes[k] {
|
||||
continue
|
||||
}
|
||||
CreateChange(&changes, Modified, k,
|
||||
lValues[k].GetValueNode(), rValues[k].GetValueNode(), false,
|
||||
lValues[k].GetValue(), lValues[k].GetValue())
|
||||
// check left example hashes
|
||||
for k := range lHashes {
|
||||
rhash := rHashes[k]
|
||||
if rhash == "" {
|
||||
CreateChange(&changes, ObjectRemoved, k,
|
||||
lValues[k].GetValueNode(), nil, false,
|
||||
lValues[k].GetValue(), nil)
|
||||
continue
|
||||
}
|
||||
if lHashes[k] == rHashes[k] {
|
||||
continue
|
||||
}
|
||||
CreateChange(&changes, Modified, k,
|
||||
lValues[k].GetValueNode(), rValues[k].GetValueNode(), false,
|
||||
lValues[k].GetValue(), lValues[k].GetValue())
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//check right example hashes
|
||||
for k := range rHashes {
|
||||
lhash := lHashes[k]
|
||||
if lhash == "" {
|
||||
CreateChange(&changes, ObjectAdded, k,
|
||||
nil, lValues[k].GetValueNode(), false,
|
||||
nil, lValues[k].GetValue())
|
||||
continue
|
||||
}
|
||||
}
|
||||
//check right example hashes
|
||||
for k := range rHashes {
|
||||
lhash := lHashes[k]
|
||||
if lhash == "" {
|
||||
CreateChange(&changes, ObjectAdded, k,
|
||||
nil, lValues[k].GetValueNode(), false,
|
||||
nil, lValues[k].GetValue())
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
ex := new(ExamplesChanges)
|
||||
ex.PropertyChanges = NewPropertyChanges(changes)
|
||||
if ex.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return ex
|
||||
ex := new(ExamplesChanges)
|
||||
ex.PropertyChanges = NewPropertyChanges(changes)
|
||||
if ex.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return ex
|
||||
}
|
||||
|
||||
@@ -4,108 +4,108 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompareExamplesV2(t *testing.T) {
|
||||
|
||||
left := `summary: magic herbs`
|
||||
right := `summary: cure all`
|
||||
left := `summary: magic herbs`
|
||||
right := `summary: cure all`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v2.Examples
|
||||
var rDoc v2.Examples
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v2.Examples
|
||||
var rDoc v2.Examples
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
extChanges := CompareExamplesV2(&lDoc, &rDoc)
|
||||
assert.Equal(t, extChanges.TotalChanges(), 1)
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.SummaryLabel, extChanges.Changes[0].Property)
|
||||
assert.Equal(t, "magic herbs", extChanges.Changes[0].Original)
|
||||
assert.Equal(t, "cure all", extChanges.Changes[0].New)
|
||||
extChanges := CompareExamplesV2(&lDoc, &rDoc)
|
||||
assert.Equal(t, extChanges.TotalChanges(), 1)
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.SummaryLabel, extChanges.Changes[0].Property)
|
||||
assert.Equal(t, "magic herbs", extChanges.Changes[0].Original)
|
||||
assert.Equal(t, "cure all", extChanges.Changes[0].New)
|
||||
}
|
||||
|
||||
func TestCompareExamplesV2_Add(t *testing.T) {
|
||||
|
||||
left := `summary: magic herbs`
|
||||
right := `summary: magic herbs
|
||||
left := `summary: magic herbs`
|
||||
right := `summary: magic herbs
|
||||
yummy: coffee`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v2.Examples
|
||||
var rDoc v2.Examples
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v2.Examples
|
||||
var rDoc v2.Examples
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
extChanges := CompareExamplesV2(&lDoc, &rDoc)
|
||||
assert.Equal(t, extChanges.TotalChanges(), 1)
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
|
||||
extChanges := CompareExamplesV2(&lDoc, &rDoc)
|
||||
assert.Equal(t, extChanges.TotalChanges(), 1)
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
|
||||
}
|
||||
|
||||
func TestCompareExamplesV2_Remove(t *testing.T) {
|
||||
|
||||
left := `summary: magic herbs`
|
||||
right := `summary: magic herbs
|
||||
left := `summary: magic herbs`
|
||||
right := `summary: magic herbs
|
||||
yummy: coffee`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v2.Examples
|
||||
var rDoc v2.Examples
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v2.Examples
|
||||
var rDoc v2.Examples
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
extChanges := CompareExamplesV2(&rDoc, &lDoc)
|
||||
assert.Equal(t, extChanges.TotalChanges(), 1)
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
|
||||
extChanges := CompareExamplesV2(&rDoc, &lDoc)
|
||||
assert.Equal(t, extChanges.TotalChanges(), 1)
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
|
||||
}
|
||||
|
||||
func TestCompareExamplesV2_Identical(t *testing.T) {
|
||||
|
||||
left := `summary: magic herbs`
|
||||
right := left
|
||||
left := `summary: magic herbs`
|
||||
right := left
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v2.Examples
|
||||
var rDoc v2.Examples
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v2.Examples
|
||||
var rDoc v2.Examples
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
extChanges := CompareExamplesV2(&rDoc, &lDoc)
|
||||
extChanges := CompareExamplesV2(&rDoc, &lDoc)
|
||||
assert.Nil(t, extChanges)
|
||||
}
|
||||
|
||||
@@ -4,28 +4,28 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"strings"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ExtensionChanges represents any changes to custom extensions defined for an OpenAPI object.
|
||||
type ExtensionChanges struct {
|
||||
*PropertyChanges
|
||||
*PropertyChanges
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Extension objects
|
||||
func (e *ExtensionChanges) GetAllChanges() []*Change {
|
||||
return e.Changes
|
||||
return e.Changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the total number of object extensions that were made.
|
||||
func (e *ExtensionChanges) TotalChanges() int {
|
||||
return e.PropertyChanges.TotalChanges()
|
||||
return e.PropertyChanges.TotalChanges()
|
||||
}
|
||||
|
||||
// TotalBreakingChanges always returns 0 for Extension objects, they are non-binding.
|
||||
func (e *ExtensionChanges) TotalBreakingChanges() int {
|
||||
return 0
|
||||
return 0
|
||||
}
|
||||
|
||||
// CompareExtensions will compare a left and right map of Tag/ValueReference models for any changes to
|
||||
@@ -36,62 +36,62 @@ func (e *ExtensionChanges) TotalBreakingChanges() int {
|
||||
// there is currently no support for knowing anything changed - so it is ignored.
|
||||
func CompareExtensions(l, r map[low.KeyReference[string]]low.ValueReference[any]) *ExtensionChanges {
|
||||
|
||||
// look at the original and then look through the new.
|
||||
seenLeft := make(map[string]*low.ValueReference[any])
|
||||
seenRight := make(map[string]*low.ValueReference[any])
|
||||
for i := range l {
|
||||
h := l[i]
|
||||
seenLeft[strings.ToLower(i.Value)] = &h
|
||||
}
|
||||
for i := range r {
|
||||
h := r[i]
|
||||
seenRight[strings.ToLower(i.Value)] = &h
|
||||
}
|
||||
// look at the original and then look through the new.
|
||||
seenLeft := make(map[string]*low.ValueReference[any])
|
||||
seenRight := make(map[string]*low.ValueReference[any])
|
||||
for i := range l {
|
||||
h := l[i]
|
||||
seenLeft[strings.ToLower(i.Value)] = &h
|
||||
}
|
||||
for i := range r {
|
||||
h := r[i]
|
||||
seenRight[strings.ToLower(i.Value)] = &h
|
||||
}
|
||||
|
||||
var changes []*Change
|
||||
for i := range seenLeft {
|
||||
var changes []*Change
|
||||
for i := range seenLeft {
|
||||
|
||||
CheckForObjectAdditionOrRemoval[any](seenLeft, seenRight, i, &changes, false, true)
|
||||
CheckForObjectAdditionOrRemoval[any](seenLeft, seenRight, i, &changes, false, true)
|
||||
|
||||
if seenRight[i] != nil {
|
||||
var props []*PropertyCheck
|
||||
if seenRight[i] != nil {
|
||||
var props []*PropertyCheck
|
||||
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: seenLeft[i].ValueNode,
|
||||
RightNode: seenRight[i].ValueNode,
|
||||
Label: i,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: seenLeft[i].Value,
|
||||
New: seenRight[i].Value,
|
||||
})
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: seenLeft[i].ValueNode,
|
||||
RightNode: seenRight[i].ValueNode,
|
||||
Label: i,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: seenLeft[i].Value,
|
||||
New: seenRight[i].Value,
|
||||
})
|
||||
|
||||
// check properties
|
||||
CheckProperties(props)
|
||||
}
|
||||
}
|
||||
for i := range seenRight {
|
||||
if seenLeft[i] == nil {
|
||||
CheckForObjectAdditionOrRemoval[any](seenLeft, seenRight, i, &changes, false, true)
|
||||
}
|
||||
}
|
||||
ex := new(ExtensionChanges)
|
||||
ex.PropertyChanges = NewPropertyChanges(changes)
|
||||
if ex.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return ex
|
||||
// check properties
|
||||
CheckProperties(props)
|
||||
}
|
||||
}
|
||||
for i := range seenRight {
|
||||
if seenLeft[i] == nil {
|
||||
CheckForObjectAdditionOrRemoval[any](seenLeft, seenRight, i, &changes, false, true)
|
||||
}
|
||||
}
|
||||
ex := new(ExtensionChanges)
|
||||
ex.PropertyChanges = NewPropertyChanges(changes)
|
||||
if ex.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return ex
|
||||
}
|
||||
|
||||
// CheckExtensions is a helper method to un-pack a left and right model that contains extensions. Once unpacked
|
||||
// the extensions are compared and returns a pointer to ExtensionChanges. If nothing changed, nil is returned.
|
||||
func CheckExtensions[T low.HasExtensions[T]](l, r T) *ExtensionChanges {
|
||||
var lExt, rExt map[low.KeyReference[string]]low.ValueReference[any]
|
||||
if len(l.GetExtensions()) > 0 {
|
||||
lExt = l.GetExtensions()
|
||||
}
|
||||
if len(r.GetExtensions()) > 0 {
|
||||
rExt = r.GetExtensions()
|
||||
}
|
||||
return CompareExtensions(lExt, rExt)
|
||||
var lExt, rExt map[low.KeyReference[string]]low.ValueReference[any]
|
||||
if len(l.GetExtensions()) > 0 {
|
||||
lExt = l.GetExtensions()
|
||||
}
|
||||
if len(r.GetExtensions()) > 0 {
|
||||
rExt = r.GetExtensions()
|
||||
}
|
||||
return CompareExtensions(lExt, rExt)
|
||||
}
|
||||
|
||||
@@ -4,79 +4,79 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// ExternalDocChanges represents changes made to any ExternalDoc object from an OpenAPI document.
|
||||
type ExternalDocChanges struct {
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Example objects
|
||||
func (e *ExternalDocChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, e.Changes...)
|
||||
if e.ExtensionChanges != nil {
|
||||
changes = append(changes, e.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, e.Changes...)
|
||||
if e.ExtensionChanges != nil {
|
||||
changes = append(changes, e.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns a count of everything that changed
|
||||
func (e *ExternalDocChanges) TotalChanges() int {
|
||||
c := e.PropertyChanges.TotalChanges()
|
||||
if e.ExtensionChanges != nil {
|
||||
c += e.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := e.PropertyChanges.TotalChanges()
|
||||
if e.ExtensionChanges != nil {
|
||||
c += e.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges always returns 0 for ExternalDoc objects, they are non-binding.
|
||||
func (e *ExternalDocChanges) TotalBreakingChanges() int {
|
||||
return 0
|
||||
return 0
|
||||
}
|
||||
|
||||
// CompareExternalDocs will compare a left (original) and a right (new) slice of ValueReference
|
||||
// nodes for any changes between them. If there are changes, then a pointer to ExternalDocChanges
|
||||
// is returned, otherwise if nothing changed - then nil is returned.
|
||||
func CompareExternalDocs(l, r *base.ExternalDoc) *ExternalDocChanges {
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
|
||||
// URL
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.URL.ValueNode,
|
||||
RightNode: r.URL.ValueNode,
|
||||
Label: v3.URLLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// URL
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.URL.ValueNode,
|
||||
RightNode: r.URL.ValueNode,
|
||||
Label: v3.URLLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// description.
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Description.ValueNode,
|
||||
RightNode: r.Description.ValueNode,
|
||||
Label: v3.DescriptionLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// description.
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Description.ValueNode,
|
||||
RightNode: r.Description.ValueNode,
|
||||
Label: v3.DescriptionLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// check everything.
|
||||
CheckProperties(props)
|
||||
// check everything.
|
||||
CheckProperties(props)
|
||||
|
||||
dc := new(ExternalDocChanges)
|
||||
dc.PropertyChanges = NewPropertyChanges(changes)
|
||||
dc := new(ExternalDocChanges)
|
||||
dc.PropertyChanges = NewPropertyChanges(changes)
|
||||
|
||||
// check extensions
|
||||
dc.ExtensionChanges = CheckExtensions(l, r)
|
||||
if dc.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return dc
|
||||
// check extensions
|
||||
dc.ExtensionChanges = CheckExtensions(l, r)
|
||||
if dc.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return dc
|
||||
}
|
||||
|
||||
@@ -4,277 +4,277 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"reflect"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// HeaderChanges represents changes made between two Header objects. Supports both Swagger and OpenAPI header
|
||||
// objects, V2 only property Items is broken out into its own.
|
||||
type HeaderChanges struct {
|
||||
*PropertyChanges
|
||||
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||
ExamplesChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
*PropertyChanges
|
||||
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||
ExamplesChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
|
||||
// Items only supported by Swagger (V2)
|
||||
ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
// Items only supported by Swagger (V2)
|
||||
ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Header objects
|
||||
func (h *HeaderChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, h.Changes...)
|
||||
for k := range h.ExamplesChanges {
|
||||
changes = append(changes, h.ExamplesChanges[k].GetAllChanges()...)
|
||||
}
|
||||
for k := range h.ContentChanges {
|
||||
changes = append(changes, h.ContentChanges[k].GetAllChanges()...)
|
||||
}
|
||||
if h.ExtensionChanges != nil {
|
||||
changes = append(changes, h.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
if h.SchemaChanges != nil {
|
||||
changes = append(changes, h.SchemaChanges.GetAllChanges()...)
|
||||
}
|
||||
if h.ItemsChanges != nil {
|
||||
changes = append(changes, h.ItemsChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, h.Changes...)
|
||||
for k := range h.ExamplesChanges {
|
||||
changes = append(changes, h.ExamplesChanges[k].GetAllChanges()...)
|
||||
}
|
||||
for k := range h.ContentChanges {
|
||||
changes = append(changes, h.ContentChanges[k].GetAllChanges()...)
|
||||
}
|
||||
if h.ExtensionChanges != nil {
|
||||
changes = append(changes, h.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
if h.SchemaChanges != nil {
|
||||
changes = append(changes, h.SchemaChanges.GetAllChanges()...)
|
||||
}
|
||||
if h.ItemsChanges != nil {
|
||||
changes = append(changes, h.ItemsChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the total number of changes made between two Header objects.
|
||||
func (h *HeaderChanges) TotalChanges() int {
|
||||
c := h.PropertyChanges.TotalChanges()
|
||||
for k := range h.ExamplesChanges {
|
||||
c += h.ExamplesChanges[k].TotalChanges()
|
||||
}
|
||||
for k := range h.ContentChanges {
|
||||
c += h.ContentChanges[k].TotalChanges()
|
||||
}
|
||||
if h.ExtensionChanges != nil {
|
||||
c += h.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
if h.SchemaChanges != nil {
|
||||
c += h.SchemaChanges.TotalChanges()
|
||||
}
|
||||
if h.ItemsChanges != nil {
|
||||
c += h.ItemsChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := h.PropertyChanges.TotalChanges()
|
||||
for k := range h.ExamplesChanges {
|
||||
c += h.ExamplesChanges[k].TotalChanges()
|
||||
}
|
||||
for k := range h.ContentChanges {
|
||||
c += h.ContentChanges[k].TotalChanges()
|
||||
}
|
||||
if h.ExtensionChanges != nil {
|
||||
c += h.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
if h.SchemaChanges != nil {
|
||||
c += h.SchemaChanges.TotalChanges()
|
||||
}
|
||||
if h.ItemsChanges != nil {
|
||||
c += h.ItemsChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the total number of breaking changes made between two Header instances.
|
||||
func (h *HeaderChanges) TotalBreakingChanges() int {
|
||||
c := h.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range h.ContentChanges {
|
||||
c += h.ContentChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
if h.ItemsChanges != nil {
|
||||
c += h.ItemsChanges.TotalBreakingChanges()
|
||||
}
|
||||
if h.SchemaChanges != nil {
|
||||
c += h.SchemaChanges.TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
c := h.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range h.ContentChanges {
|
||||
c += h.ContentChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
if h.ItemsChanges != nil {
|
||||
c += h.ItemsChanges.TotalBreakingChanges()
|
||||
}
|
||||
if h.SchemaChanges != nil {
|
||||
c += h.SchemaChanges.TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// shared header properties
|
||||
func addOpenAPIHeaderProperties(left, right low.OpenAPIHeader, changes *[]*Change) []*PropertyCheck {
|
||||
var props []*PropertyCheck
|
||||
var props []*PropertyCheck
|
||||
|
||||
// style
|
||||
addPropertyCheck(&props, left.GetStyle().ValueNode, right.GetStyle().ValueNode,
|
||||
left.GetStyle(), right.GetStyle(), changes, v3.StyleLabel, false)
|
||||
// style
|
||||
addPropertyCheck(&props, left.GetStyle().ValueNode, right.GetStyle().ValueNode,
|
||||
left.GetStyle(), right.GetStyle(), changes, v3.StyleLabel, false)
|
||||
|
||||
// allow reserved
|
||||
addPropertyCheck(&props, left.GetAllowReserved().ValueNode, right.GetAllowReserved().ValueNode,
|
||||
left.GetAllowReserved(), right.GetAllowReserved(), changes, v3.AllowReservedLabel, false)
|
||||
// allow reserved
|
||||
addPropertyCheck(&props, left.GetAllowReserved().ValueNode, right.GetAllowReserved().ValueNode,
|
||||
left.GetAllowReserved(), right.GetAllowReserved(), changes, v3.AllowReservedLabel, false)
|
||||
|
||||
// allow empty value
|
||||
addPropertyCheck(&props, left.GetAllowEmptyValue().ValueNode, right.GetAllowEmptyValue().ValueNode,
|
||||
left.GetAllowEmptyValue(), right.GetAllowEmptyValue(), changes, v3.AllowEmptyValueLabel, true)
|
||||
// allow empty value
|
||||
addPropertyCheck(&props, left.GetAllowEmptyValue().ValueNode, right.GetAllowEmptyValue().ValueNode,
|
||||
left.GetAllowEmptyValue(), right.GetAllowEmptyValue(), changes, v3.AllowEmptyValueLabel, true)
|
||||
|
||||
// explode
|
||||
addPropertyCheck(&props, left.GetExplode().ValueNode, right.GetExplode().ValueNode,
|
||||
left.GetExplode(), right.GetExplode(), changes, v3.ExplodeLabel, false)
|
||||
// explode
|
||||
addPropertyCheck(&props, left.GetExplode().ValueNode, right.GetExplode().ValueNode,
|
||||
left.GetExplode(), right.GetExplode(), changes, v3.ExplodeLabel, false)
|
||||
|
||||
// example
|
||||
addPropertyCheck(&props, left.GetExample().ValueNode, right.GetExample().ValueNode,
|
||||
left.GetExample(), right.GetExample(), changes, v3.ExampleLabel, false)
|
||||
// example
|
||||
addPropertyCheck(&props, left.GetExample().ValueNode, right.GetExample().ValueNode,
|
||||
left.GetExample(), right.GetExample(), changes, v3.ExampleLabel, false)
|
||||
|
||||
// deprecated
|
||||
addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode,
|
||||
left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false)
|
||||
// deprecated
|
||||
addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode,
|
||||
left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false)
|
||||
|
||||
// required
|
||||
addPropertyCheck(&props, left.GetRequired().ValueNode, right.GetRequired().ValueNode,
|
||||
left.GetRequired(), right.GetRequired(), changes, v3.RequiredLabel, true)
|
||||
// required
|
||||
addPropertyCheck(&props, left.GetRequired().ValueNode, right.GetRequired().ValueNode,
|
||||
left.GetRequired(), right.GetRequired(), changes, v3.RequiredLabel, true)
|
||||
|
||||
return props
|
||||
return props
|
||||
}
|
||||
|
||||
// swagger only properties
|
||||
func addSwaggerHeaderProperties(left, right low.SwaggerHeader, changes *[]*Change) []*PropertyCheck {
|
||||
var props []*PropertyCheck
|
||||
var props []*PropertyCheck
|
||||
|
||||
// type
|
||||
addPropertyCheck(&props, left.GetType().ValueNode, right.GetType().ValueNode,
|
||||
left.GetType(), right.GetType(), changes, v3.TypeLabel, true)
|
||||
// type
|
||||
addPropertyCheck(&props, left.GetType().ValueNode, right.GetType().ValueNode,
|
||||
left.GetType(), right.GetType(), changes, v3.TypeLabel, true)
|
||||
|
||||
// format
|
||||
addPropertyCheck(&props, left.GetFormat().ValueNode, right.GetFormat().ValueNode,
|
||||
left.GetFormat(), right.GetFormat(), changes, v3.FormatLabel, true)
|
||||
// format
|
||||
addPropertyCheck(&props, left.GetFormat().ValueNode, right.GetFormat().ValueNode,
|
||||
left.GetFormat(), right.GetFormat(), changes, v3.FormatLabel, true)
|
||||
|
||||
// collection format
|
||||
addPropertyCheck(&props, left.GetCollectionFormat().ValueNode, right.GetCollectionFormat().ValueNode,
|
||||
left.GetCollectionFormat(), right.GetCollectionFormat(), changes, v3.CollectionFormatLabel, true)
|
||||
// collection format
|
||||
addPropertyCheck(&props, left.GetCollectionFormat().ValueNode, right.GetCollectionFormat().ValueNode,
|
||||
left.GetCollectionFormat(), right.GetCollectionFormat(), changes, v3.CollectionFormatLabel, true)
|
||||
|
||||
// maximum
|
||||
addPropertyCheck(&props, left.GetMaximum().ValueNode, right.GetMaximum().ValueNode,
|
||||
left.GetMaximum(), right.GetMaximum(), changes, v3.MaximumLabel, true)
|
||||
// maximum
|
||||
addPropertyCheck(&props, left.GetMaximum().ValueNode, right.GetMaximum().ValueNode,
|
||||
left.GetMaximum(), right.GetMaximum(), changes, v3.MaximumLabel, true)
|
||||
|
||||
// minimum
|
||||
addPropertyCheck(&props, left.GetMinimum().ValueNode, right.GetMinimum().ValueNode,
|
||||
left.GetMinimum(), right.GetMinimum(), changes, v3.MinimumLabel, true)
|
||||
// minimum
|
||||
addPropertyCheck(&props, left.GetMinimum().ValueNode, right.GetMinimum().ValueNode,
|
||||
left.GetMinimum(), right.GetMinimum(), changes, v3.MinimumLabel, true)
|
||||
|
||||
// exclusive maximum
|
||||
addPropertyCheck(&props, left.GetExclusiveMaximum().ValueNode, right.GetExclusiveMaximum().ValueNode,
|
||||
left.GetExclusiveMaximum(), right.GetExclusiveMaximum(), changes, v3.ExclusiveMaximumLabel, true)
|
||||
// exclusive maximum
|
||||
addPropertyCheck(&props, left.GetExclusiveMaximum().ValueNode, right.GetExclusiveMaximum().ValueNode,
|
||||
left.GetExclusiveMaximum(), right.GetExclusiveMaximum(), changes, v3.ExclusiveMaximumLabel, true)
|
||||
|
||||
// exclusive minimum
|
||||
addPropertyCheck(&props, left.GetExclusiveMinimum().ValueNode, right.GetExclusiveMinimum().ValueNode,
|
||||
left.GetExclusiveMinimum(), right.GetExclusiveMinimum(), changes, v3.ExclusiveMinimumLabel, true)
|
||||
// exclusive minimum
|
||||
addPropertyCheck(&props, left.GetExclusiveMinimum().ValueNode, right.GetExclusiveMinimum().ValueNode,
|
||||
left.GetExclusiveMinimum(), right.GetExclusiveMinimum(), changes, v3.ExclusiveMinimumLabel, true)
|
||||
|
||||
// max length
|
||||
addPropertyCheck(&props, left.GetMaxLength().ValueNode, right.GetMaxLength().ValueNode,
|
||||
left.GetMaxLength(), right.GetMaxLength(), changes, v3.MaxLengthLabel, true)
|
||||
// max length
|
||||
addPropertyCheck(&props, left.GetMaxLength().ValueNode, right.GetMaxLength().ValueNode,
|
||||
left.GetMaxLength(), right.GetMaxLength(), changes, v3.MaxLengthLabel, true)
|
||||
|
||||
// min length
|
||||
addPropertyCheck(&props, left.GetMinLength().ValueNode, right.GetMinLength().ValueNode,
|
||||
left.GetMinLength(), right.GetMinLength(), changes, v3.MinLengthLabel, true)
|
||||
// min length
|
||||
addPropertyCheck(&props, left.GetMinLength().ValueNode, right.GetMinLength().ValueNode,
|
||||
left.GetMinLength(), right.GetMinLength(), changes, v3.MinLengthLabel, true)
|
||||
|
||||
// pattern
|
||||
addPropertyCheck(&props, left.GetPattern().ValueNode, right.GetPattern().ValueNode,
|
||||
left.GetPattern(), right.GetPattern(), changes, v3.PatternLabel, true)
|
||||
// pattern
|
||||
addPropertyCheck(&props, left.GetPattern().ValueNode, right.GetPattern().ValueNode,
|
||||
left.GetPattern(), right.GetPattern(), changes, v3.PatternLabel, true)
|
||||
|
||||
// max items
|
||||
addPropertyCheck(&props, left.GetMaxItems().ValueNode, right.GetMaxItems().ValueNode,
|
||||
left.GetMaxItems(), right.GetMaxItems(), changes, v3.MaxItemsLabel, true)
|
||||
// max items
|
||||
addPropertyCheck(&props, left.GetMaxItems().ValueNode, right.GetMaxItems().ValueNode,
|
||||
left.GetMaxItems(), right.GetMaxItems(), changes, v3.MaxItemsLabel, true)
|
||||
|
||||
// min items
|
||||
addPropertyCheck(&props, left.GetMinItems().ValueNode, right.GetMinItems().ValueNode,
|
||||
left.GetMinItems(), right.GetMinItems(), changes, v3.MinItemsLabel, true)
|
||||
// min items
|
||||
addPropertyCheck(&props, left.GetMinItems().ValueNode, right.GetMinItems().ValueNode,
|
||||
left.GetMinItems(), right.GetMinItems(), changes, v3.MinItemsLabel, true)
|
||||
|
||||
// unique items
|
||||
addPropertyCheck(&props, left.GetUniqueItems().ValueNode, right.GetUniqueItems().ValueNode,
|
||||
left.GetUniqueItems(), right.GetUniqueItems(), changes, v3.UniqueItemsLabel, true)
|
||||
// unique items
|
||||
addPropertyCheck(&props, left.GetUniqueItems().ValueNode, right.GetUniqueItems().ValueNode,
|
||||
left.GetUniqueItems(), right.GetUniqueItems(), changes, v3.UniqueItemsLabel, true)
|
||||
|
||||
// multiple of
|
||||
addPropertyCheck(&props, left.GetMultipleOf().ValueNode, right.GetMultipleOf().ValueNode,
|
||||
left.GetMultipleOf(), right.GetMultipleOf(), changes, v3.MultipleOfLabel, true)
|
||||
// multiple of
|
||||
addPropertyCheck(&props, left.GetMultipleOf().ValueNode, right.GetMultipleOf().ValueNode,
|
||||
left.GetMultipleOf(), right.GetMultipleOf(), changes, v3.MultipleOfLabel, true)
|
||||
|
||||
return props
|
||||
return props
|
||||
}
|
||||
|
||||
// common header properties
|
||||
func addCommonHeaderProperties(left, right low.HasDescription, changes *[]*Change) []*PropertyCheck {
|
||||
var props []*PropertyCheck
|
||||
var props []*PropertyCheck
|
||||
|
||||
// description
|
||||
addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode,
|
||||
left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false)
|
||||
// description
|
||||
addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode,
|
||||
left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false)
|
||||
|
||||
return props
|
||||
return props
|
||||
}
|
||||
|
||||
// CompareHeadersV2 is a Swagger compatible, typed signature used for other generic functions. It simply
|
||||
// wraps CompareHeaders and provides nothing other that a typed interface.
|
||||
func CompareHeadersV2(l, r *v2.Header) *HeaderChanges {
|
||||
return CompareHeaders(l, r)
|
||||
return CompareHeaders(l, r)
|
||||
}
|
||||
|
||||
// CompareHeadersV3 is an OpenAPI 3+ compatible, typed signature used for other generic functions. It simply
|
||||
// wraps CompareHeaders and provides nothing other that a typed interface.
|
||||
func CompareHeadersV3(l, r *v3.Header) *HeaderChanges {
|
||||
return CompareHeaders(l, r)
|
||||
return CompareHeaders(l, r)
|
||||
}
|
||||
|
||||
// CompareHeaders will compare left and right Header objects (any version of Swagger or OpenAPI) and return
|
||||
// a pointer to HeaderChanges with anything that has changed, or nil if nothing changed.
|
||||
func CompareHeaders(l, r any) *HeaderChanges {
|
||||
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
hc := new(HeaderChanges)
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
hc := new(HeaderChanges)
|
||||
|
||||
// handle swagger.
|
||||
if reflect.TypeOf(&v2.Header{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Header{}) == reflect.TypeOf(r) {
|
||||
lHeader := l.(*v2.Header)
|
||||
rHeader := r.(*v2.Header)
|
||||
// handle swagger.
|
||||
if reflect.TypeOf(&v2.Header{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Header{}) == reflect.TypeOf(r) {
|
||||
lHeader := l.(*v2.Header)
|
||||
rHeader := r.(*v2.Header)
|
||||
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lHeader, rHeader) {
|
||||
return nil
|
||||
}
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lHeader, rHeader) {
|
||||
return nil
|
||||
}
|
||||
|
||||
props = append(props, addCommonHeaderProperties(lHeader, rHeader, &changes)...)
|
||||
props = append(props, addSwaggerHeaderProperties(lHeader, rHeader, &changes)...)
|
||||
props = append(props, addCommonHeaderProperties(lHeader, rHeader, &changes)...)
|
||||
props = append(props, addSwaggerHeaderProperties(lHeader, rHeader, &changes)...)
|
||||
|
||||
// enum
|
||||
if len(lHeader.Enum.Value) > 0 || len(rHeader.Enum.Value) > 0 {
|
||||
ExtractRawValueSliceChanges(lHeader.Enum.Value, rHeader.Enum.Value, &changes, v3.EnumLabel, true)
|
||||
}
|
||||
// enum
|
||||
if len(lHeader.Enum.Value) > 0 || len(rHeader.Enum.Value) > 0 {
|
||||
ExtractRawValueSliceChanges(lHeader.Enum.Value, rHeader.Enum.Value, &changes, v3.EnumLabel, true)
|
||||
}
|
||||
|
||||
// items
|
||||
if !lHeader.Items.IsEmpty() && !rHeader.Items.IsEmpty() {
|
||||
if !low.AreEqual(lHeader.Items.Value, rHeader.Items.Value) {
|
||||
hc.ItemsChanges = CompareItems(lHeader.Items.Value, rHeader.Items.Value)
|
||||
}
|
||||
}
|
||||
if lHeader.Items.IsEmpty() && !rHeader.Items.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.ItemsLabel, nil,
|
||||
rHeader.Items.ValueNode, true, nil, rHeader.Items.Value)
|
||||
}
|
||||
if !lHeader.Items.IsEmpty() && rHeader.Items.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel, lHeader.Items.ValueNode,
|
||||
nil, true, lHeader.Items.Value, nil)
|
||||
}
|
||||
hc.ExtensionChanges = CompareExtensions(lHeader.Extensions, rHeader.Extensions)
|
||||
}
|
||||
// items
|
||||
if !lHeader.Items.IsEmpty() && !rHeader.Items.IsEmpty() {
|
||||
if !low.AreEqual(lHeader.Items.Value, rHeader.Items.Value) {
|
||||
hc.ItemsChanges = CompareItems(lHeader.Items.Value, rHeader.Items.Value)
|
||||
}
|
||||
}
|
||||
if lHeader.Items.IsEmpty() && !rHeader.Items.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.ItemsLabel, nil,
|
||||
rHeader.Items.ValueNode, true, nil, rHeader.Items.Value)
|
||||
}
|
||||
if !lHeader.Items.IsEmpty() && rHeader.Items.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel, lHeader.Items.ValueNode,
|
||||
nil, true, lHeader.Items.Value, nil)
|
||||
}
|
||||
hc.ExtensionChanges = CompareExtensions(lHeader.Extensions, rHeader.Extensions)
|
||||
}
|
||||
|
||||
// handle OpenAPI
|
||||
if reflect.TypeOf(&v3.Header{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Header{}) == reflect.TypeOf(r) {
|
||||
lHeader := l.(*v3.Header)
|
||||
rHeader := r.(*v3.Header)
|
||||
// handle OpenAPI
|
||||
if reflect.TypeOf(&v3.Header{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Header{}) == reflect.TypeOf(r) {
|
||||
lHeader := l.(*v3.Header)
|
||||
rHeader := r.(*v3.Header)
|
||||
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lHeader, rHeader) {
|
||||
return nil
|
||||
}
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lHeader, rHeader) {
|
||||
return nil
|
||||
}
|
||||
|
||||
props = append(props, addCommonHeaderProperties(lHeader, rHeader, &changes)...)
|
||||
props = append(props, addOpenAPIHeaderProperties(lHeader, rHeader, &changes)...)
|
||||
props = append(props, addCommonHeaderProperties(lHeader, rHeader, &changes)...)
|
||||
props = append(props, addOpenAPIHeaderProperties(lHeader, rHeader, &changes)...)
|
||||
|
||||
// header
|
||||
if !lHeader.Schema.IsEmpty() || !rHeader.Schema.IsEmpty() {
|
||||
hc.SchemaChanges = CompareSchemas(lHeader.Schema.Value, rHeader.Schema.Value)
|
||||
}
|
||||
// header
|
||||
if !lHeader.Schema.IsEmpty() || !rHeader.Schema.IsEmpty() {
|
||||
hc.SchemaChanges = CompareSchemas(lHeader.Schema.Value, rHeader.Schema.Value)
|
||||
}
|
||||
|
||||
// examples
|
||||
hc.ExamplesChanges = CheckMapForChanges(lHeader.Examples.Value, rHeader.Examples.Value,
|
||||
&changes, v3.ExamplesLabel, CompareExamples)
|
||||
// examples
|
||||
hc.ExamplesChanges = CheckMapForChanges(lHeader.Examples.Value, rHeader.Examples.Value,
|
||||
&changes, v3.ExamplesLabel, CompareExamples)
|
||||
|
||||
// content
|
||||
hc.ContentChanges = CheckMapForChanges(lHeader.Content.Value, rHeader.Content.Value,
|
||||
&changes, v3.ContentLabel, CompareMediaTypes)
|
||||
// content
|
||||
hc.ContentChanges = CheckMapForChanges(lHeader.Content.Value, rHeader.Content.Value,
|
||||
&changes, v3.ContentLabel, CompareMediaTypes)
|
||||
|
||||
hc.ExtensionChanges = CompareExtensions(lHeader.Extensions, rHeader.Extensions)
|
||||
hc.ExtensionChanges = CompareExtensions(lHeader.Extensions, rHeader.Extensions)
|
||||
|
||||
}
|
||||
CheckProperties(props)
|
||||
hc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return hc
|
||||
}
|
||||
CheckProperties(props)
|
||||
hc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return hc
|
||||
}
|
||||
|
||||
@@ -17,15 +17,15 @@ type InfoChanges struct {
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Info objects
|
||||
func (i *InfoChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, i.Changes...)
|
||||
if i.ContactChanges != nil {
|
||||
changes = append(changes, i.ContactChanges.GetAllChanges()...)
|
||||
}
|
||||
if i.LicenseChanges != nil {
|
||||
changes = append(changes, i.LicenseChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, i.Changes...)
|
||||
if i.ContactChanges != nil {
|
||||
changes = append(changes, i.ContactChanges.GetAllChanges()...)
|
||||
}
|
||||
if i.LicenseChanges != nil {
|
||||
changes = append(changes, i.LicenseChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges represents the total number of changes made to an Info object.
|
||||
|
||||
@@ -4,17 +4,17 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompareInfo_DescriptionAdded(t *testing.T) {
|
||||
|
||||
left := `title: a nice spec
|
||||
left := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
@@ -23,7 +23,7 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
right := `title: a nice spec
|
||||
right := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
description: this is a description
|
||||
@@ -33,29 +33,29 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.DescriptionLabel, extChanges.Changes[0].Property)
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.DescriptionLabel, extChanges.Changes[0].Property)
|
||||
}
|
||||
|
||||
func TestCompareInfo_TitleRemoved(t *testing.T) {
|
||||
|
||||
left := `title: a nice spec
|
||||
left := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
description: this is a description
|
||||
@@ -65,7 +65,7 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
right := `termsOfService: https://pb33f.io/terms
|
||||
right := `termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
description: this is a description
|
||||
contact:
|
||||
@@ -74,29 +74,29 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.TitleLabel, extChanges.Changes[0].Property)
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.TitleLabel, extChanges.Changes[0].Property)
|
||||
}
|
||||
|
||||
func TestCompareInfo_VersionModified(t *testing.T) {
|
||||
|
||||
left := `title: a nice spec
|
||||
left := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
@@ -105,7 +105,7 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
right := `title: a nice spec
|
||||
right := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '99.99'
|
||||
contact:
|
||||
@@ -114,29 +114,29 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.VersionLabel, extChanges.Changes[0].Property)
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.VersionLabel, extChanges.Changes[0].Property)
|
||||
}
|
||||
|
||||
func TestCompareInfo_RemoveLicense(t *testing.T) {
|
||||
|
||||
left := `title: a nice spec
|
||||
left := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
@@ -145,43 +145,43 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
right := `title: a nice spec
|
||||
right := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
name: buckaroo
|
||||
email: buckaroo@pb33f.io`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.LicenseLabel, extChanges.Changes[0].Property)
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.LicenseLabel, extChanges.Changes[0].Property)
|
||||
}
|
||||
|
||||
func TestCompareInfo_AddLicense(t *testing.T) {
|
||||
|
||||
left := `title: a nice spec
|
||||
left := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
name: buckaroo
|
||||
email: buckaroo@pb33f.io`
|
||||
|
||||
right := `title: a nice spec
|
||||
right := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
@@ -190,29 +190,29 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.LicenseLabel, extChanges.Changes[0].Property)
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.LicenseLabel, extChanges.Changes[0].Property)
|
||||
}
|
||||
|
||||
func TestCompareInfo_LicenseChanged(t *testing.T) {
|
||||
|
||||
left := `title: a nice spec
|
||||
left := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
@@ -221,7 +221,7 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
right := `title: a nice spec
|
||||
right := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
@@ -230,35 +230,35 @@ contact:
|
||||
license:
|
||||
name: Apache`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, Modified, extChanges.LicenseChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.NameLabel, extChanges.LicenseChanges.Changes[0].Property)
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, Modified, extChanges.LicenseChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.NameLabel, extChanges.LicenseChanges.Changes[0].Property)
|
||||
}
|
||||
|
||||
func TestCompareInfo_AddContact(t *testing.T) {
|
||||
|
||||
left := `title: a nice spec
|
||||
left := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
right := `title: a nice spec
|
||||
right := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
@@ -267,29 +267,29 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.ContactLabel, extChanges.Changes[0].Property)
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.ContactLabel, extChanges.Changes[0].Property)
|
||||
}
|
||||
|
||||
func TestCompareInfo_RemoveContact(t *testing.T) {
|
||||
|
||||
left := `title: a nice spec
|
||||
left := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
@@ -298,35 +298,35 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
right := `title: a nice spec
|
||||
right := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.ContactLabel, extChanges.Changes[0].Property)
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.ContactLabel, extChanges.Changes[0].Property)
|
||||
}
|
||||
|
||||
func TestCompareInfo_ContactModified(t *testing.T) {
|
||||
|
||||
left := `title: a nice spec
|
||||
left := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
@@ -335,7 +335,7 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
right := `title: a nice spec
|
||||
right := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
@@ -344,30 +344,30 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, Modified, extChanges.ContactChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.NameLabel, extChanges.ContactChanges.Changes[0].Property)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, Modified, extChanges.ContactChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, v3.NameLabel, extChanges.ContactChanges.Changes[0].Property)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
}
|
||||
|
||||
func TestCompareInfo_Equal(t *testing.T) {
|
||||
|
||||
left := `title: a nice spec
|
||||
left := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
@@ -376,7 +376,7 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
right := `title: a nice spec
|
||||
right := `title: a nice spec
|
||||
termsOfService: https://pb33f.io/terms
|
||||
version: '1.2.3'
|
||||
contact:
|
||||
@@ -385,17 +385,17 @@ contact:
|
||||
license:
|
||||
name: MIT`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.Info
|
||||
var rDoc base.Info
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareInfo(&lDoc, &rDoc)
|
||||
|
||||
@@ -4,45 +4,45 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// ItemsChanges represent changes found between a left (original) and right (modified) object. Items is only
|
||||
// used by Swagger documents.
|
||||
type ItemsChanges struct {
|
||||
*PropertyChanges
|
||||
ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
*PropertyChanges
|
||||
ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Items objects
|
||||
func (i *ItemsChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, i.Changes...)
|
||||
if i.ItemsChanges != nil {
|
||||
changes = append(changes, i.ItemsChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, i.Changes...)
|
||||
if i.ItemsChanges != nil {
|
||||
changes = append(changes, i.ItemsChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the total number of changes found between two Items objects
|
||||
// This is a recursive function because Items can contain Items. Be careful!
|
||||
func (i *ItemsChanges) TotalChanges() int {
|
||||
c := i.PropertyChanges.TotalChanges()
|
||||
if i.ItemsChanges != nil {
|
||||
c += i.ItemsChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := i.PropertyChanges.TotalChanges()
|
||||
if i.ItemsChanges != nil {
|
||||
c += i.ItemsChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the total number of breaking changes found between two Swagger Items objects
|
||||
// This is a recursive method, Items are recursive, be careful!
|
||||
func (i *ItemsChanges) TotalBreakingChanges() int {
|
||||
c := i.PropertyChanges.TotalBreakingChanges()
|
||||
if i.ItemsChanges != nil {
|
||||
c += i.ItemsChanges.TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
c := i.PropertyChanges.TotalBreakingChanges()
|
||||
if i.ItemsChanges != nil {
|
||||
c += i.ItemsChanges.TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CompareItems compares two sets of Swagger Item objects. If there are any changes found then a pointer to
|
||||
@@ -52,37 +52,37 @@ func (i *ItemsChanges) TotalBreakingChanges() int {
|
||||
// runaway code if not using the resolver's circular reference checking.
|
||||
func CompareItems(l, r *v2.Items) *ItemsChanges {
|
||||
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
|
||||
ic := new(ItemsChanges)
|
||||
ic := new(ItemsChanges)
|
||||
|
||||
// header is identical to items, except for a description.
|
||||
props = append(props, addSwaggerHeaderProperties(l, r, &changes)...)
|
||||
CheckProperties(props)
|
||||
// header is identical to items, except for a description.
|
||||
props = append(props, addSwaggerHeaderProperties(l, r, &changes)...)
|
||||
CheckProperties(props)
|
||||
|
||||
if !l.Items.IsEmpty() && !r.Items.IsEmpty() {
|
||||
// inline, check hashes, if they don't match, compare.
|
||||
if l.Items.Value.Hash() != r.Items.Value.Hash() {
|
||||
// compare.
|
||||
ic.ItemsChanges = CompareItems(l.Items.Value, r.Items.Value)
|
||||
}
|
||||
if !l.Items.IsEmpty() && !r.Items.IsEmpty() {
|
||||
// inline, check hashes, if they don't match, compare.
|
||||
if l.Items.Value.Hash() != r.Items.Value.Hash() {
|
||||
// compare.
|
||||
ic.ItemsChanges = CompareItems(l.Items.Value, r.Items.Value)
|
||||
}
|
||||
|
||||
}
|
||||
if l.Items.IsEmpty() && !r.Items.IsEmpty() {
|
||||
// added items
|
||||
CreateChange(&changes, PropertyAdded, v3.ItemsLabel,
|
||||
nil, r.Items.GetValueNode(), true, nil, r.Items.GetValue())
|
||||
}
|
||||
if !l.Items.IsEmpty() && r.Items.IsEmpty() {
|
||||
// removed items
|
||||
CreateChange(&changes, PropertyRemoved, v3.ItemsLabel,
|
||||
l.Items.GetValueNode(), nil, true, l.Items.GetValue(),
|
||||
nil)
|
||||
}
|
||||
ic.PropertyChanges = NewPropertyChanges(changes)
|
||||
if ic.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return ic
|
||||
}
|
||||
if l.Items.IsEmpty() && !r.Items.IsEmpty() {
|
||||
// added items
|
||||
CreateChange(&changes, PropertyAdded, v3.ItemsLabel,
|
||||
nil, r.Items.GetValueNode(), true, nil, r.Items.GetValue())
|
||||
}
|
||||
if !l.Items.IsEmpty() && r.Items.IsEmpty() {
|
||||
// removed items
|
||||
CreateChange(&changes, PropertyRemoved, v3.ItemsLabel,
|
||||
l.Items.GetValueNode(), nil, true, l.Items.GetValue(),
|
||||
nil)
|
||||
}
|
||||
ic.PropertyChanges = NewPropertyChanges(changes)
|
||||
if ic.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return ic
|
||||
}
|
||||
|
||||
@@ -4,136 +4,136 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompareItems(t *testing.T) {
|
||||
|
||||
left := `type: string`
|
||||
left := `type: string`
|
||||
|
||||
right := `type: int`
|
||||
right := `type: int`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v2.Items
|
||||
var rDoc v2.Items
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v2.Items
|
||||
var rDoc v2.Items
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
changes := CompareItems(&lDoc, &rDoc)
|
||||
assert.NotNil(t, changes)
|
||||
assert.Equal(t, 1, changes.TotalChanges())
|
||||
assert.Len(t, changes.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, changes.TotalBreakingChanges())
|
||||
assert.Equal(t, v3.TypeLabel, changes.Changes[0].Property)
|
||||
// compare.
|
||||
changes := CompareItems(&lDoc, &rDoc)
|
||||
assert.NotNil(t, changes)
|
||||
assert.Equal(t, 1, changes.TotalChanges())
|
||||
assert.Len(t, changes.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, changes.TotalBreakingChanges())
|
||||
assert.Equal(t, v3.TypeLabel, changes.Changes[0].Property)
|
||||
}
|
||||
|
||||
func TestCompareItems_RecursiveCheck(t *testing.T) {
|
||||
|
||||
left := `type: string
|
||||
left := `type: string
|
||||
items:
|
||||
type: string`
|
||||
|
||||
right := `type: int
|
||||
right := `type: int
|
||||
items:
|
||||
type: int`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v2.Items
|
||||
var rDoc v2.Items
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v2.Items
|
||||
var rDoc v2.Items
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
changes := CompareItems(&lDoc, &rDoc)
|
||||
assert.NotNil(t, changes)
|
||||
assert.Equal(t, 2, changes.TotalChanges())
|
||||
assert.Len(t, changes.GetAllChanges(), 2)
|
||||
assert.Equal(t, 2, changes.TotalBreakingChanges())
|
||||
assert.Equal(t, 1, changes.ItemsChanges.TotalChanges())
|
||||
assert.Equal(t, v3.TypeLabel, changes.Changes[0].Property)
|
||||
// compare.
|
||||
changes := CompareItems(&lDoc, &rDoc)
|
||||
assert.NotNil(t, changes)
|
||||
assert.Equal(t, 2, changes.TotalChanges())
|
||||
assert.Len(t, changes.GetAllChanges(), 2)
|
||||
assert.Equal(t, 2, changes.TotalBreakingChanges())
|
||||
assert.Equal(t, 1, changes.ItemsChanges.TotalChanges())
|
||||
assert.Equal(t, v3.TypeLabel, changes.Changes[0].Property)
|
||||
}
|
||||
|
||||
func TestCompareItems_AddItems(t *testing.T) {
|
||||
|
||||
left := `type: int`
|
||||
left := `type: int`
|
||||
|
||||
right := `type: int
|
||||
right := `type: int
|
||||
items:
|
||||
type: int`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v2.Items
|
||||
var rDoc v2.Items
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v2.Items
|
||||
var rDoc v2.Items
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
changes := CompareItems(&lDoc, &rDoc)
|
||||
assert.NotNil(t, changes)
|
||||
assert.Equal(t, 1, changes.TotalChanges())
|
||||
assert.Len(t, changes.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, changes.TotalBreakingChanges())
|
||||
assert.Equal(t, v3.ItemsLabel, changes.Changes[0].Property)
|
||||
assert.Equal(t, PropertyAdded, changes.Changes[0].ChangeType)
|
||||
// compare.
|
||||
changes := CompareItems(&lDoc, &rDoc)
|
||||
assert.NotNil(t, changes)
|
||||
assert.Equal(t, 1, changes.TotalChanges())
|
||||
assert.Len(t, changes.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, changes.TotalBreakingChanges())
|
||||
assert.Equal(t, v3.ItemsLabel, changes.Changes[0].Property)
|
||||
assert.Equal(t, PropertyAdded, changes.Changes[0].ChangeType)
|
||||
}
|
||||
|
||||
func TestCompareItems_RemoveItems(t *testing.T) {
|
||||
|
||||
left := `type: int`
|
||||
left := `type: int`
|
||||
|
||||
right := `type: int
|
||||
right := `type: int
|
||||
items:
|
||||
type: int`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v2.Items
|
||||
var rDoc v2.Items
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v2.Items
|
||||
var rDoc v2.Items
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
changes := CompareItems(&rDoc, &lDoc)
|
||||
assert.NotNil(t, changes)
|
||||
assert.Equal(t, 1, changes.TotalChanges())
|
||||
assert.Len(t, changes.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, changes.TotalBreakingChanges())
|
||||
assert.Equal(t, v3.ItemsLabel, changes.Changes[0].Property)
|
||||
assert.Equal(t, PropertyRemoved, changes.Changes[0].ChangeType)
|
||||
// compare.
|
||||
changes := CompareItems(&rDoc, &lDoc)
|
||||
assert.NotNil(t, changes)
|
||||
assert.Equal(t, 1, changes.TotalChanges())
|
||||
assert.Len(t, changes.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, changes.TotalBreakingChanges())
|
||||
assert.Equal(t, v3.ItemsLabel, changes.Changes[0].Property)
|
||||
assert.Equal(t, PropertyRemoved, changes.Changes[0].ChangeType)
|
||||
}
|
||||
|
||||
func TestCompareItems_RefVsInlineIdentical(t *testing.T) {
|
||||
|
||||
left := `swagger: 2.0
|
||||
left := `swagger: 2.0
|
||||
definitions:
|
||||
thing:
|
||||
type: string
|
||||
@@ -149,7 +149,7 @@ paths:
|
||||
items:
|
||||
$ref: '#/definitions/thing'`
|
||||
|
||||
right := `swagger: 2.0
|
||||
right := `swagger: 2.0
|
||||
definitions:
|
||||
thing:
|
||||
type: string
|
||||
@@ -165,15 +165,15 @@ paths:
|
||||
items:
|
||||
type: bool`
|
||||
|
||||
leftDoc, rightDoc := test_BuildDocv2(left, right)
|
||||
leftDoc, rightDoc := test_BuildDocv2(left, right)
|
||||
|
||||
// extract left reference schema and non reference schema.
|
||||
lItems := leftDoc.Paths.Value.FindPath("/a/path").Value.Get.Value.Parameters.
|
||||
Value[0].Value.Items.Value
|
||||
rItems := rightDoc.Paths.Value.FindPath("/a/path").Value.Get.Value.Parameters.
|
||||
Value[0].Value.Items.Value
|
||||
// extract left reference schema and non reference schema.
|
||||
lItems := leftDoc.Paths.Value.FindPath("/a/path").Value.Get.Value.Parameters.
|
||||
Value[0].Value.Items.Value
|
||||
rItems := rightDoc.Paths.Value.FindPath("/a/path").Value.Get.Value.Parameters.
|
||||
Value[0].Value.Items.Value
|
||||
|
||||
// compare.
|
||||
changes := CompareItems(lItems, rItems)
|
||||
// compare.
|
||||
changes := CompareItems(lItems, rItems)
|
||||
assert.Nil(t, changes)
|
||||
}
|
||||
|
||||
@@ -4,28 +4,28 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// LicenseChanges represent changes to a License object that is a child of Info object. Part of an OpenAPI document
|
||||
type LicenseChanges struct {
|
||||
*PropertyChanges
|
||||
*PropertyChanges
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between License objects
|
||||
func (l *LicenseChanges) GetAllChanges() []*Change {
|
||||
return l.Changes
|
||||
return l.Changes
|
||||
}
|
||||
|
||||
// TotalChanges represents the total number of changes made to a License instance.
|
||||
func (l *LicenseChanges) TotalChanges() int {
|
||||
return l.PropertyChanges.TotalChanges()
|
||||
return l.PropertyChanges.TotalChanges()
|
||||
}
|
||||
|
||||
// TotalBreakingChanges always returns 0 for License objects, they are non-binding.
|
||||
func (l *LicenseChanges) TotalBreakingChanges() int {
|
||||
return 0
|
||||
return 0
|
||||
}
|
||||
|
||||
// CompareLicense will check a left (original) and right (new) License object for any changes. If there
|
||||
@@ -33,38 +33,38 @@ func (l *LicenseChanges) TotalBreakingChanges() int {
|
||||
// returns nil.
|
||||
func CompareLicense(l, r *base.License) *LicenseChanges {
|
||||
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
|
||||
// check URL
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.URL.ValueNode,
|
||||
RightNode: r.URL.ValueNode,
|
||||
Label: v3.URLLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// check URL
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.URL.ValueNode,
|
||||
RightNode: r.URL.ValueNode,
|
||||
Label: v3.URLLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// check name
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Name.ValueNode,
|
||||
RightNode: r.Name.ValueNode,
|
||||
Label: v3.NameLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// check name
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Name.ValueNode,
|
||||
RightNode: r.Name.ValueNode,
|
||||
Label: v3.NameLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// check everything.
|
||||
CheckProperties(props)
|
||||
// check everything.
|
||||
CheckProperties(props)
|
||||
|
||||
lc := new(LicenseChanges)
|
||||
lc.PropertyChanges = NewPropertyChanges(changes)
|
||||
if lc.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return lc
|
||||
lc := new(LicenseChanges)
|
||||
lc.PropertyChanges = NewPropertyChanges(changes)
|
||||
if lc.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return lc
|
||||
}
|
||||
|
||||
@@ -4,157 +4,157 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// LinkChanges represent changes made between two OpenAPI Link Objects.
|
||||
type LinkChanges struct {
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
ServerChanges *ServerChanges `json:"server,omitempty" yaml:"server,omitempty"`
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
ServerChanges *ServerChanges `json:"server,omitempty" yaml:"server,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Link objects
|
||||
func (l *LinkChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, l.Changes...)
|
||||
if l.ServerChanges != nil {
|
||||
changes = append(changes, l.ServerChanges.GetAllChanges()...)
|
||||
}
|
||||
if l.ExtensionChanges != nil {
|
||||
changes = append(changes, l.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, l.Changes...)
|
||||
if l.ServerChanges != nil {
|
||||
changes = append(changes, l.ServerChanges.GetAllChanges()...)
|
||||
}
|
||||
if l.ExtensionChanges != nil {
|
||||
changes = append(changes, l.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the total changes made between OpenAPI Link objects
|
||||
func (l *LinkChanges) TotalChanges() int {
|
||||
c := l.PropertyChanges.TotalChanges()
|
||||
if l.ExtensionChanges != nil {
|
||||
c += l.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
if l.ServerChanges != nil {
|
||||
c += l.ServerChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := l.PropertyChanges.TotalChanges()
|
||||
if l.ExtensionChanges != nil {
|
||||
c += l.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
if l.ServerChanges != nil {
|
||||
c += l.ServerChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the number of breaking changes made between two OpenAPI Link Objects
|
||||
func (l *LinkChanges) TotalBreakingChanges() int {
|
||||
c := l.PropertyChanges.TotalBreakingChanges()
|
||||
if l.ServerChanges != nil {
|
||||
c += l.ServerChanges.TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
c := l.PropertyChanges.TotalBreakingChanges()
|
||||
if l.ServerChanges != nil {
|
||||
c += l.ServerChanges.TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CompareLinks checks a left and right OpenAPI Link for any changes. If they are found, returns a pointer to
|
||||
// LinkChanges, and returns nil if nothing is found.
|
||||
func CompareLinks(l, r *v3.Link) *LinkChanges {
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
|
||||
// operation ref
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.OperationRef.ValueNode,
|
||||
RightNode: r.OperationRef.ValueNode,
|
||||
Label: v3.OperationRefLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// operation ref
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.OperationRef.ValueNode,
|
||||
RightNode: r.OperationRef.ValueNode,
|
||||
Label: v3.OperationRefLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// operation id
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.OperationId.ValueNode,
|
||||
RightNode: r.OperationId.ValueNode,
|
||||
Label: v3.OperationIdLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// operation id
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.OperationId.ValueNode,
|
||||
RightNode: r.OperationId.ValueNode,
|
||||
Label: v3.OperationIdLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// request body
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.RequestBody.ValueNode,
|
||||
RightNode: r.RequestBody.ValueNode,
|
||||
Label: v3.RequestBodyLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// request body
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.RequestBody.ValueNode,
|
||||
RightNode: r.RequestBody.ValueNode,
|
||||
Label: v3.RequestBodyLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// description
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Description.ValueNode,
|
||||
RightNode: r.Description.ValueNode,
|
||||
Label: v3.DescriptionLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// description
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Description.ValueNode,
|
||||
RightNode: r.Description.ValueNode,
|
||||
Label: v3.DescriptionLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
CheckProperties(props)
|
||||
lc := new(LinkChanges)
|
||||
lc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
CheckProperties(props)
|
||||
lc := new(LinkChanges)
|
||||
lc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
|
||||
// server
|
||||
if !l.Server.IsEmpty() && !r.Server.IsEmpty() {
|
||||
if !low.AreEqual(l.Server.Value, r.Server.Value) {
|
||||
lc.ServerChanges = CompareServers(l.Server.Value, r.Server.Value)
|
||||
}
|
||||
}
|
||||
if !l.Server.IsEmpty() && r.Server.IsEmpty() {
|
||||
CreateChange(&changes, PropertyRemoved, v3.ServerLabel,
|
||||
l.Server.ValueNode, nil, true,
|
||||
l.Server.Value, nil)
|
||||
}
|
||||
if l.Server.IsEmpty() && !r.Server.IsEmpty() {
|
||||
CreateChange(&changes, PropertyAdded, v3.ServerLabel,
|
||||
nil, r.Server.ValueNode, true,
|
||||
nil, r.Server.Value)
|
||||
}
|
||||
// server
|
||||
if !l.Server.IsEmpty() && !r.Server.IsEmpty() {
|
||||
if !low.AreEqual(l.Server.Value, r.Server.Value) {
|
||||
lc.ServerChanges = CompareServers(l.Server.Value, r.Server.Value)
|
||||
}
|
||||
}
|
||||
if !l.Server.IsEmpty() && r.Server.IsEmpty() {
|
||||
CreateChange(&changes, PropertyRemoved, v3.ServerLabel,
|
||||
l.Server.ValueNode, nil, true,
|
||||
l.Server.Value, nil)
|
||||
}
|
||||
if l.Server.IsEmpty() && !r.Server.IsEmpty() {
|
||||
CreateChange(&changes, PropertyAdded, v3.ServerLabel,
|
||||
nil, r.Server.ValueNode, true,
|
||||
nil, r.Server.Value)
|
||||
}
|
||||
|
||||
// parameters
|
||||
lValues := make(map[string]low.ValueReference[string])
|
||||
rValues := make(map[string]low.ValueReference[string])
|
||||
for i := range l.Parameters.Value {
|
||||
lValues[i.Value] = l.Parameters.Value[i]
|
||||
}
|
||||
for i := range r.Parameters.Value {
|
||||
rValues[i.Value] = r.Parameters.Value[i]
|
||||
}
|
||||
for k := range lValues {
|
||||
if _, ok := rValues[k]; !ok {
|
||||
CreateChange(&changes, ObjectRemoved, v3.ParametersLabel,
|
||||
lValues[k].ValueNode, nil, true,
|
||||
k, nil)
|
||||
continue
|
||||
}
|
||||
if lValues[k].Value != rValues[k].Value {
|
||||
CreateChange(&changes, Modified, v3.ParametersLabel,
|
||||
lValues[k].ValueNode, rValues[k].ValueNode, true,
|
||||
k, k)
|
||||
}
|
||||
// parameters
|
||||
lValues := make(map[string]low.ValueReference[string])
|
||||
rValues := make(map[string]low.ValueReference[string])
|
||||
for i := range l.Parameters.Value {
|
||||
lValues[i.Value] = l.Parameters.Value[i]
|
||||
}
|
||||
for i := range r.Parameters.Value {
|
||||
rValues[i.Value] = r.Parameters.Value[i]
|
||||
}
|
||||
for k := range lValues {
|
||||
if _, ok := rValues[k]; !ok {
|
||||
CreateChange(&changes, ObjectRemoved, v3.ParametersLabel,
|
||||
lValues[k].ValueNode, nil, true,
|
||||
k, nil)
|
||||
continue
|
||||
}
|
||||
if lValues[k].Value != rValues[k].Value {
|
||||
CreateChange(&changes, Modified, v3.ParametersLabel,
|
||||
lValues[k].ValueNode, rValues[k].ValueNode, true,
|
||||
k, k)
|
||||
}
|
||||
|
||||
}
|
||||
for k := range rValues {
|
||||
if _, ok := lValues[k]; !ok {
|
||||
CreateChange(&changes, ObjectAdded, v3.ParametersLabel,
|
||||
nil, rValues[k].ValueNode, true,
|
||||
nil, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
for k := range rValues {
|
||||
if _, ok := lValues[k]; !ok {
|
||||
CreateChange(&changes, ObjectAdded, v3.ParametersLabel,
|
||||
nil, rValues[k].ValueNode, true,
|
||||
nil, k)
|
||||
}
|
||||
}
|
||||
|
||||
lc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return lc
|
||||
lc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return lc
|
||||
}
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompareLinks(t *testing.T) {
|
||||
|
||||
left := `operationId: someOperation
|
||||
left := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
server:
|
||||
@@ -21,29 +21,29 @@ server:
|
||||
parameters:
|
||||
nice: rice`
|
||||
|
||||
right := left
|
||||
right := left
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareLinks(&lDoc, &rDoc)
|
||||
assert.Nil(t, extChanges)
|
||||
// compare.
|
||||
extChanges := CompareLinks(&lDoc, &rDoc)
|
||||
assert.Nil(t, extChanges)
|
||||
|
||||
}
|
||||
|
||||
func TestCompareLinks_ModifyExtension(t *testing.T) {
|
||||
|
||||
left := `operationId: someOperation
|
||||
left := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
server:
|
||||
@@ -52,7 +52,7 @@ parameters:
|
||||
nice: rice
|
||||
x-cake: tasty`
|
||||
|
||||
right := `operationId: someOperation
|
||||
right := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
server:
|
||||
@@ -61,30 +61,30 @@ parameters:
|
||||
nice: rice
|
||||
x-cake: very tasty`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareLinks(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, Modified, extChanges.ExtensionChanges.Changes[0].ChangeType)
|
||||
// compare.
|
||||
extChanges := CompareLinks(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, Modified, extChanges.ExtensionChanges.Changes[0].ChangeType)
|
||||
|
||||
}
|
||||
|
||||
func TestCompareLinks_ModifyServer(t *testing.T) {
|
||||
|
||||
left := `operationId: someOperation
|
||||
left := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
server:
|
||||
@@ -92,7 +92,7 @@ server:
|
||||
parameters:
|
||||
nice: rice`
|
||||
|
||||
right := `operationId: someOperation
|
||||
right := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
server:
|
||||
@@ -100,35 +100,35 @@ server:
|
||||
parameters:
|
||||
nice: rice`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareLinks(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, Modified, extChanges.ServerChanges.Changes[0].ChangeType)
|
||||
// compare.
|
||||
extChanges := CompareLinks(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, Modified, extChanges.ServerChanges.Changes[0].ChangeType)
|
||||
}
|
||||
|
||||
func TestCompareLinks_AddServer(t *testing.T) {
|
||||
|
||||
left := `operationId: someOperation
|
||||
left := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
parameters:
|
||||
nice: rice`
|
||||
|
||||
right := `operationId: someOperation
|
||||
right := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
server:
|
||||
@@ -136,35 +136,35 @@ server:
|
||||
parameters:
|
||||
nice: rice`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareLinks(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
|
||||
// compare.
|
||||
extChanges := CompareLinks(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
|
||||
}
|
||||
|
||||
func TestCompareLinks_RemoveServer(t *testing.T) {
|
||||
|
||||
left := `operationId: someOperation
|
||||
left := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
parameters:
|
||||
nice: rice`
|
||||
|
||||
right := `operationId: someOperation
|
||||
right := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
server:
|
||||
@@ -172,29 +172,29 @@ server:
|
||||
parameters:
|
||||
nice: rice`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareLinks(&rDoc, &lDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
|
||||
// compare.
|
||||
extChanges := CompareLinks(&rDoc, &lDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
|
||||
}
|
||||
|
||||
func TestCompareLinks_ModifyParam(t *testing.T) {
|
||||
|
||||
left := `operationId: someOperation
|
||||
left := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
server:
|
||||
@@ -202,7 +202,7 @@ server:
|
||||
parameters:
|
||||
nice: cake`
|
||||
|
||||
right := `operationId: someOperation
|
||||
right := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
server:
|
||||
@@ -210,32 +210,32 @@ server:
|
||||
parameters:
|
||||
nice: rice`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareLinks(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, "nice", extChanges.Changes[0].NewObject)
|
||||
assert.Equal(t, "cake", extChanges.Changes[0].Original)
|
||||
assert.Equal(t, "rice", extChanges.Changes[0].New)
|
||||
// compare.
|
||||
extChanges := CompareLinks(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, "nice", extChanges.Changes[0].NewObject)
|
||||
assert.Equal(t, "cake", extChanges.Changes[0].Original)
|
||||
assert.Equal(t, "rice", extChanges.Changes[0].New)
|
||||
}
|
||||
|
||||
func TestCompareLinks_AddParam(t *testing.T) {
|
||||
|
||||
left := `operationId: someOperation
|
||||
left := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
server:
|
||||
@@ -243,7 +243,7 @@ server:
|
||||
parameters:
|
||||
nice: cake`
|
||||
|
||||
right := `operationId: someOperation
|
||||
right := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
server:
|
||||
@@ -252,31 +252,31 @@ parameters:
|
||||
nice: cake
|
||||
hot: pizza`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareLinks(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, "hot", extChanges.Changes[0].NewObject)
|
||||
assert.Equal(t, "pizza", extChanges.Changes[0].New)
|
||||
// compare.
|
||||
extChanges := CompareLinks(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, "hot", extChanges.Changes[0].NewObject)
|
||||
assert.Equal(t, "pizza", extChanges.Changes[0].New)
|
||||
}
|
||||
|
||||
func TestCompareLinks_RemoveParam(t *testing.T) {
|
||||
|
||||
left := `operationId: someOperation
|
||||
left := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
server:
|
||||
@@ -284,7 +284,7 @@ server:
|
||||
parameters:
|
||||
nice: cake`
|
||||
|
||||
right := `operationId: someOperation
|
||||
right := `operationId: someOperation
|
||||
requestBody: expression-says-what
|
||||
description: a nice link
|
||||
server:
|
||||
@@ -293,24 +293,24 @@ parameters:
|
||||
nice: cake
|
||||
hot: pizza`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.Link
|
||||
var rDoc v3.Link
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareLinks(&rDoc, &lDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, "hot", extChanges.Changes[0].OriginalObject)
|
||||
// compare.
|
||||
extChanges := CompareLinks(&rDoc, &lDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, "hot", extChanges.Changes[0].OriginalObject)
|
||||
assert.Equal(t, "pizza", extChanges.Changes[0].Original)
|
||||
}
|
||||
|
||||
@@ -4,146 +4,146 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/utils"
|
||||
"gopkg.in/yaml.v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/utils"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// MediaTypeChanges represent changes made between two OpenAPI MediaType instances.
|
||||
type MediaTypeChanges struct {
|
||||
*PropertyChanges
|
||||
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
ExampleChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
EncodingChanges map[string]*EncodingChanges `json:"encoding,omitempty" yaml:"encoding,omitempty"`
|
||||
*PropertyChanges
|
||||
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
ExampleChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
EncodingChanges map[string]*EncodingChanges `json:"encoding,omitempty" yaml:"encoding,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between MediaType objects
|
||||
func (m *MediaTypeChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, m.Changes...)
|
||||
if m.SchemaChanges != nil {
|
||||
changes = append(changes, m.SchemaChanges.GetAllChanges()...)
|
||||
}
|
||||
for k := range m.ExampleChanges {
|
||||
changes = append(changes, m.ExampleChanges[k].GetAllChanges()...)
|
||||
}
|
||||
for k := range m.EncodingChanges {
|
||||
changes = append(changes, m.EncodingChanges[k].GetAllChanges()...)
|
||||
}
|
||||
if m.ExtensionChanges != nil {
|
||||
changes = append(changes, m.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, m.Changes...)
|
||||
if m.SchemaChanges != nil {
|
||||
changes = append(changes, m.SchemaChanges.GetAllChanges()...)
|
||||
}
|
||||
for k := range m.ExampleChanges {
|
||||
changes = append(changes, m.ExampleChanges[k].GetAllChanges()...)
|
||||
}
|
||||
for k := range m.EncodingChanges {
|
||||
changes = append(changes, m.EncodingChanges[k].GetAllChanges()...)
|
||||
}
|
||||
if m.ExtensionChanges != nil {
|
||||
changes = append(changes, m.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the total number of changes between two MediaType instances.
|
||||
func (m *MediaTypeChanges) TotalChanges() int {
|
||||
c := m.PropertyChanges.TotalChanges()
|
||||
for k := range m.ExampleChanges {
|
||||
c += m.ExampleChanges[k].TotalChanges()
|
||||
}
|
||||
if m.SchemaChanges != nil {
|
||||
c += m.SchemaChanges.TotalChanges()
|
||||
}
|
||||
if len(m.EncodingChanges) > 0 {
|
||||
for i := range m.EncodingChanges {
|
||||
c += m.EncodingChanges[i].TotalChanges()
|
||||
}
|
||||
}
|
||||
if m.ExtensionChanges != nil {
|
||||
c += m.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := m.PropertyChanges.TotalChanges()
|
||||
for k := range m.ExampleChanges {
|
||||
c += m.ExampleChanges[k].TotalChanges()
|
||||
}
|
||||
if m.SchemaChanges != nil {
|
||||
c += m.SchemaChanges.TotalChanges()
|
||||
}
|
||||
if len(m.EncodingChanges) > 0 {
|
||||
for i := range m.EncodingChanges {
|
||||
c += m.EncodingChanges[i].TotalChanges()
|
||||
}
|
||||
}
|
||||
if m.ExtensionChanges != nil {
|
||||
c += m.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the total number of breaking changes made between two MediaType instances.
|
||||
func (m *MediaTypeChanges) TotalBreakingChanges() int {
|
||||
c := m.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range m.ExampleChanges {
|
||||
c += m.ExampleChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
if m.SchemaChanges != nil {
|
||||
c += m.SchemaChanges.TotalBreakingChanges()
|
||||
}
|
||||
if len(m.EncodingChanges) > 0 {
|
||||
for i := range m.EncodingChanges {
|
||||
c += m.EncodingChanges[i].TotalBreakingChanges()
|
||||
}
|
||||
}
|
||||
return c
|
||||
c := m.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range m.ExampleChanges {
|
||||
c += m.ExampleChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
if m.SchemaChanges != nil {
|
||||
c += m.SchemaChanges.TotalBreakingChanges()
|
||||
}
|
||||
if len(m.EncodingChanges) > 0 {
|
||||
for i := range m.EncodingChanges {
|
||||
c += m.EncodingChanges[i].TotalBreakingChanges()
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CompareMediaTypes compares a left and a right MediaType object for any changes. If found, a pointer to a
|
||||
// MediaTypeChanges instance is returned, otherwise nothing is returned.
|
||||
func CompareMediaTypes(l, r *v3.MediaType) *MediaTypeChanges {
|
||||
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
|
||||
mc := new(MediaTypeChanges)
|
||||
mc := new(MediaTypeChanges)
|
||||
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Example
|
||||
if !l.Example.IsEmpty() && !r.Example.IsEmpty() {
|
||||
if (utils.IsNodeMap(l.Example.ValueNode) && utils.IsNodeMap(r.Example.ValueNode)) ||
|
||||
(utils.IsNodeArray(l.Example.ValueNode) && utils.IsNodeArray(r.Example.ValueNode)) {
|
||||
render, _ := yaml.Marshal(l.Example.ValueNode)
|
||||
render, _ = utils.ConvertYAMLtoJSON(render)
|
||||
l.Example.ValueNode.Value = string(render)
|
||||
render, _ = yaml.Marshal(r.Example.ValueNode)
|
||||
render, _ = utils.ConvertYAMLtoJSON(render)
|
||||
r.Example.ValueNode.Value = string(render)
|
||||
}
|
||||
addPropertyCheck(&props, l.Example.ValueNode, r.Example.ValueNode,
|
||||
l.Example.Value, r.Example.Value, &changes, v3.ExampleLabel, false)
|
||||
// Example
|
||||
if !l.Example.IsEmpty() && !r.Example.IsEmpty() {
|
||||
if (utils.IsNodeMap(l.Example.ValueNode) && utils.IsNodeMap(r.Example.ValueNode)) ||
|
||||
(utils.IsNodeArray(l.Example.ValueNode) && utils.IsNodeArray(r.Example.ValueNode)) {
|
||||
render, _ := yaml.Marshal(l.Example.ValueNode)
|
||||
render, _ = utils.ConvertYAMLtoJSON(render)
|
||||
l.Example.ValueNode.Value = string(render)
|
||||
render, _ = yaml.Marshal(r.Example.ValueNode)
|
||||
render, _ = utils.ConvertYAMLtoJSON(render)
|
||||
r.Example.ValueNode.Value = string(render)
|
||||
}
|
||||
addPropertyCheck(&props, l.Example.ValueNode, r.Example.ValueNode,
|
||||
l.Example.Value, r.Example.Value, &changes, v3.ExampleLabel, false)
|
||||
|
||||
} else {
|
||||
} else {
|
||||
|
||||
if utils.IsNodeMap(l.Example.ValueNode) || utils.IsNodeArray(l.Example.ValueNode) {
|
||||
render, _ := yaml.Marshal(l.Example.ValueNode)
|
||||
render, _ = utils.ConvertYAMLtoJSON(render)
|
||||
l.Example.ValueNode.Value = string(render)
|
||||
}
|
||||
if utils.IsNodeMap(l.Example.ValueNode) || utils.IsNodeArray(l.Example.ValueNode) {
|
||||
render, _ := yaml.Marshal(l.Example.ValueNode)
|
||||
render, _ = utils.ConvertYAMLtoJSON(render)
|
||||
l.Example.ValueNode.Value = string(render)
|
||||
}
|
||||
|
||||
if utils.IsNodeMap(r.Example.ValueNode) || utils.IsNodeArray(r.Example.ValueNode) {
|
||||
render, _ := yaml.Marshal(r.Example.ValueNode)
|
||||
render, _ = utils.ConvertYAMLtoJSON(render)
|
||||
r.Example.ValueNode.Value = string(render)
|
||||
}
|
||||
if utils.IsNodeMap(r.Example.ValueNode) || utils.IsNodeArray(r.Example.ValueNode) {
|
||||
render, _ := yaml.Marshal(r.Example.ValueNode)
|
||||
render, _ = utils.ConvertYAMLtoJSON(render)
|
||||
r.Example.ValueNode.Value = string(render)
|
||||
}
|
||||
|
||||
addPropertyCheck(&props, l.Example.ValueNode, r.Example.ValueNode,
|
||||
l.Example.Value, r.Example.Value, &changes, v3.ExampleLabel, false)
|
||||
}
|
||||
addPropertyCheck(&props, l.Example.ValueNode, r.Example.ValueNode,
|
||||
l.Example.Value, r.Example.Value, &changes, v3.ExampleLabel, false)
|
||||
}
|
||||
|
||||
CheckProperties(props)
|
||||
CheckProperties(props)
|
||||
|
||||
// schema
|
||||
if !l.Schema.IsEmpty() && !r.Schema.IsEmpty() {
|
||||
mc.SchemaChanges = CompareSchemas(l.Schema.Value, r.Schema.Value)
|
||||
}
|
||||
if !l.Schema.IsEmpty() && r.Schema.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel, l.Schema.ValueNode,
|
||||
nil, true, l.Schema.Value, nil)
|
||||
}
|
||||
if l.Schema.IsEmpty() && !r.Schema.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.SchemaLabel, nil,
|
||||
r.Schema.ValueNode, true, nil, r.Schema.Value)
|
||||
}
|
||||
// schema
|
||||
if !l.Schema.IsEmpty() && !r.Schema.IsEmpty() {
|
||||
mc.SchemaChanges = CompareSchemas(l.Schema.Value, r.Schema.Value)
|
||||
}
|
||||
if !l.Schema.IsEmpty() && r.Schema.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel, l.Schema.ValueNode,
|
||||
nil, true, l.Schema.Value, nil)
|
||||
}
|
||||
if l.Schema.IsEmpty() && !r.Schema.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.SchemaLabel, nil,
|
||||
r.Schema.ValueNode, true, nil, r.Schema.Value)
|
||||
}
|
||||
|
||||
// examples
|
||||
mc.ExampleChanges = CheckMapForChanges(l.Examples.Value, r.Examples.Value,
|
||||
&changes, v3.ExamplesLabel, CompareExamples)
|
||||
// examples
|
||||
mc.ExampleChanges = CheckMapForChanges(l.Examples.Value, r.Examples.Value,
|
||||
&changes, v3.ExamplesLabel, CompareExamples)
|
||||
|
||||
// encoding
|
||||
mc.EncodingChanges = CheckMapForChanges(l.Encoding.Value, r.Encoding.Value,
|
||||
&changes, v3.EncodingLabel, CompareEncoding)
|
||||
// encoding
|
||||
mc.EncodingChanges = CheckMapForChanges(l.Encoding.Value, r.Encoding.Value,
|
||||
&changes, v3.EncodingLabel, CompareEncoding)
|
||||
|
||||
mc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
mc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return mc
|
||||
mc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
mc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return mc
|
||||
}
|
||||
|
||||
@@ -4,254 +4,254 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// OAuthFlowsChanges represents changes found between two OpenAPI OAuthFlows objects.
|
||||
type OAuthFlowsChanges struct {
|
||||
*PropertyChanges
|
||||
ImplicitChanges *OAuthFlowChanges `json:"implicit,omitempty" yaml:"implicit,omitempty"`
|
||||
PasswordChanges *OAuthFlowChanges `json:"password,omitempty" yaml:"password,omitempty"`
|
||||
ClientCredentialsChanges *OAuthFlowChanges `json:"clientCredentials,omitempty" yaml:"clientCredentials,omitempty"`
|
||||
AuthorizationCodeChanges *OAuthFlowChanges `json:"authCode,omitempty" yaml:"authCode,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
*PropertyChanges
|
||||
ImplicitChanges *OAuthFlowChanges `json:"implicit,omitempty" yaml:"implicit,omitempty"`
|
||||
PasswordChanges *OAuthFlowChanges `json:"password,omitempty" yaml:"password,omitempty"`
|
||||
ClientCredentialsChanges *OAuthFlowChanges `json:"clientCredentials,omitempty" yaml:"clientCredentials,omitempty"`
|
||||
AuthorizationCodeChanges *OAuthFlowChanges `json:"authCode,omitempty" yaml:"authCode,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between OAuthFlows objects
|
||||
func (o *OAuthFlowsChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, o.Changes...)
|
||||
if o.ImplicitChanges != nil {
|
||||
changes = append(changes, o.ImplicitChanges.GetAllChanges()...)
|
||||
}
|
||||
if o.PasswordChanges != nil {
|
||||
changes = append(changes, o.PasswordChanges.GetAllChanges()...)
|
||||
}
|
||||
if o.ClientCredentialsChanges != nil {
|
||||
changes = append(changes, o.ClientCredentialsChanges.GetAllChanges()...)
|
||||
}
|
||||
if o.AuthorizationCodeChanges != nil {
|
||||
changes = append(changes, o.AuthorizationCodeChanges.GetAllChanges()...)
|
||||
}
|
||||
if o.ExtensionChanges != nil {
|
||||
changes = append(changes, o.ImplicitChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, o.Changes...)
|
||||
if o.ImplicitChanges != nil {
|
||||
changes = append(changes, o.ImplicitChanges.GetAllChanges()...)
|
||||
}
|
||||
if o.PasswordChanges != nil {
|
||||
changes = append(changes, o.PasswordChanges.GetAllChanges()...)
|
||||
}
|
||||
if o.ClientCredentialsChanges != nil {
|
||||
changes = append(changes, o.ClientCredentialsChanges.GetAllChanges()...)
|
||||
}
|
||||
if o.AuthorizationCodeChanges != nil {
|
||||
changes = append(changes, o.AuthorizationCodeChanges.GetAllChanges()...)
|
||||
}
|
||||
if o.ExtensionChanges != nil {
|
||||
changes = append(changes, o.ImplicitChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the number of changes made between two OAuthFlows instances.
|
||||
func (o *OAuthFlowsChanges) TotalChanges() int {
|
||||
c := o.PropertyChanges.TotalChanges()
|
||||
if o.ImplicitChanges != nil {
|
||||
c += o.ImplicitChanges.TotalChanges()
|
||||
}
|
||||
if o.PasswordChanges != nil {
|
||||
c += o.PasswordChanges.TotalChanges()
|
||||
}
|
||||
if o.ClientCredentialsChanges != nil {
|
||||
c += o.ClientCredentialsChanges.TotalChanges()
|
||||
}
|
||||
if o.AuthorizationCodeChanges != nil {
|
||||
c += o.AuthorizationCodeChanges.TotalChanges()
|
||||
}
|
||||
if o.ExtensionChanges != nil {
|
||||
c += o.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := o.PropertyChanges.TotalChanges()
|
||||
if o.ImplicitChanges != nil {
|
||||
c += o.ImplicitChanges.TotalChanges()
|
||||
}
|
||||
if o.PasswordChanges != nil {
|
||||
c += o.PasswordChanges.TotalChanges()
|
||||
}
|
||||
if o.ClientCredentialsChanges != nil {
|
||||
c += o.ClientCredentialsChanges.TotalChanges()
|
||||
}
|
||||
if o.AuthorizationCodeChanges != nil {
|
||||
c += o.AuthorizationCodeChanges.TotalChanges()
|
||||
}
|
||||
if o.ExtensionChanges != nil {
|
||||
c += o.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the number of breaking changes made between two OAuthFlows objects.
|
||||
func (o *OAuthFlowsChanges) TotalBreakingChanges() int {
|
||||
c := o.PropertyChanges.TotalBreakingChanges()
|
||||
if o.ImplicitChanges != nil {
|
||||
c += o.ImplicitChanges.TotalBreakingChanges()
|
||||
}
|
||||
if o.PasswordChanges != nil {
|
||||
c += o.PasswordChanges.TotalBreakingChanges()
|
||||
}
|
||||
if o.ClientCredentialsChanges != nil {
|
||||
c += o.ClientCredentialsChanges.TotalBreakingChanges()
|
||||
}
|
||||
if o.AuthorizationCodeChanges != nil {
|
||||
c += o.AuthorizationCodeChanges.TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
c := o.PropertyChanges.TotalBreakingChanges()
|
||||
if o.ImplicitChanges != nil {
|
||||
c += o.ImplicitChanges.TotalBreakingChanges()
|
||||
}
|
||||
if o.PasswordChanges != nil {
|
||||
c += o.PasswordChanges.TotalBreakingChanges()
|
||||
}
|
||||
if o.ClientCredentialsChanges != nil {
|
||||
c += o.ClientCredentialsChanges.TotalBreakingChanges()
|
||||
}
|
||||
if o.AuthorizationCodeChanges != nil {
|
||||
c += o.AuthorizationCodeChanges.TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CompareOAuthFlows compares a left and right OAuthFlows object. If changes are found a pointer to *OAuthFlowsChanges
|
||||
// is returned, otherwise nil is returned.
|
||||
func CompareOAuthFlows(l, r *v3.OAuthFlows) *OAuthFlowsChanges {
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
|
||||
oa := new(OAuthFlowsChanges)
|
||||
var changes []*Change
|
||||
oa := new(OAuthFlowsChanges)
|
||||
var changes []*Change
|
||||
|
||||
// client credentials
|
||||
if !l.ClientCredentials.IsEmpty() && !r.ClientCredentials.IsEmpty() {
|
||||
oa.ClientCredentialsChanges = CompareOAuthFlow(l.ClientCredentials.Value, r.ClientCredentials.Value)
|
||||
}
|
||||
if !l.ClientCredentials.IsEmpty() && r.ClientCredentials.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.ClientCredentialsLabel,
|
||||
l.ClientCredentials.ValueNode, nil, true,
|
||||
l.ClientCredentials.Value, nil)
|
||||
}
|
||||
if l.ClientCredentials.IsEmpty() && !r.ClientCredentials.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.ClientCredentialsLabel,
|
||||
nil, r.ClientCredentials.ValueNode, false,
|
||||
nil, r.ClientCredentials.Value)
|
||||
}
|
||||
// client credentials
|
||||
if !l.ClientCredentials.IsEmpty() && !r.ClientCredentials.IsEmpty() {
|
||||
oa.ClientCredentialsChanges = CompareOAuthFlow(l.ClientCredentials.Value, r.ClientCredentials.Value)
|
||||
}
|
||||
if !l.ClientCredentials.IsEmpty() && r.ClientCredentials.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.ClientCredentialsLabel,
|
||||
l.ClientCredentials.ValueNode, nil, true,
|
||||
l.ClientCredentials.Value, nil)
|
||||
}
|
||||
if l.ClientCredentials.IsEmpty() && !r.ClientCredentials.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.ClientCredentialsLabel,
|
||||
nil, r.ClientCredentials.ValueNode, false,
|
||||
nil, r.ClientCredentials.Value)
|
||||
}
|
||||
|
||||
// implicit
|
||||
if !l.Implicit.IsEmpty() && !r.Implicit.IsEmpty() {
|
||||
oa.ImplicitChanges = CompareOAuthFlow(l.Implicit.Value, r.Implicit.Value)
|
||||
}
|
||||
if !l.Implicit.IsEmpty() && r.Implicit.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.ImplicitLabel,
|
||||
l.Implicit.ValueNode, nil, true,
|
||||
l.Implicit.Value, nil)
|
||||
}
|
||||
if l.Implicit.IsEmpty() && !r.Implicit.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.ImplicitLabel,
|
||||
nil, r.Implicit.ValueNode, false,
|
||||
nil, r.Implicit.Value)
|
||||
}
|
||||
// implicit
|
||||
if !l.Implicit.IsEmpty() && !r.Implicit.IsEmpty() {
|
||||
oa.ImplicitChanges = CompareOAuthFlow(l.Implicit.Value, r.Implicit.Value)
|
||||
}
|
||||
if !l.Implicit.IsEmpty() && r.Implicit.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.ImplicitLabel,
|
||||
l.Implicit.ValueNode, nil, true,
|
||||
l.Implicit.Value, nil)
|
||||
}
|
||||
if l.Implicit.IsEmpty() && !r.Implicit.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.ImplicitLabel,
|
||||
nil, r.Implicit.ValueNode, false,
|
||||
nil, r.Implicit.Value)
|
||||
}
|
||||
|
||||
// password
|
||||
if !l.Password.IsEmpty() && !r.Password.IsEmpty() {
|
||||
oa.PasswordChanges = CompareOAuthFlow(l.Password.Value, r.Password.Value)
|
||||
}
|
||||
if !l.Password.IsEmpty() && r.Password.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.PasswordLabel,
|
||||
l.Password.ValueNode, nil, true,
|
||||
l.Password.Value, nil)
|
||||
}
|
||||
if l.Password.IsEmpty() && !r.Password.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.PasswordLabel,
|
||||
nil, r.Password.ValueNode, false,
|
||||
nil, r.Password.Value)
|
||||
}
|
||||
// password
|
||||
if !l.Password.IsEmpty() && !r.Password.IsEmpty() {
|
||||
oa.PasswordChanges = CompareOAuthFlow(l.Password.Value, r.Password.Value)
|
||||
}
|
||||
if !l.Password.IsEmpty() && r.Password.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.PasswordLabel,
|
||||
l.Password.ValueNode, nil, true,
|
||||
l.Password.Value, nil)
|
||||
}
|
||||
if l.Password.IsEmpty() && !r.Password.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.PasswordLabel,
|
||||
nil, r.Password.ValueNode, false,
|
||||
nil, r.Password.Value)
|
||||
}
|
||||
|
||||
// auth code
|
||||
if !l.AuthorizationCode.IsEmpty() && !r.AuthorizationCode.IsEmpty() {
|
||||
oa.AuthorizationCodeChanges = CompareOAuthFlow(l.AuthorizationCode.Value, r.AuthorizationCode.Value)
|
||||
}
|
||||
if !l.AuthorizationCode.IsEmpty() && r.AuthorizationCode.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.AuthorizationCodeLabel,
|
||||
l.AuthorizationCode.ValueNode, nil, true,
|
||||
l.AuthorizationCode.Value, nil)
|
||||
}
|
||||
if l.AuthorizationCode.IsEmpty() && !r.AuthorizationCode.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.AuthorizationCodeLabel,
|
||||
nil, r.AuthorizationCode.ValueNode, false,
|
||||
nil, r.AuthorizationCode.Value)
|
||||
}
|
||||
oa.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
oa.PropertyChanges = NewPropertyChanges(changes)
|
||||
return oa
|
||||
// auth code
|
||||
if !l.AuthorizationCode.IsEmpty() && !r.AuthorizationCode.IsEmpty() {
|
||||
oa.AuthorizationCodeChanges = CompareOAuthFlow(l.AuthorizationCode.Value, r.AuthorizationCode.Value)
|
||||
}
|
||||
if !l.AuthorizationCode.IsEmpty() && r.AuthorizationCode.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.AuthorizationCodeLabel,
|
||||
l.AuthorizationCode.ValueNode, nil, true,
|
||||
l.AuthorizationCode.Value, nil)
|
||||
}
|
||||
if l.AuthorizationCode.IsEmpty() && !r.AuthorizationCode.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.AuthorizationCodeLabel,
|
||||
nil, r.AuthorizationCode.ValueNode, false,
|
||||
nil, r.AuthorizationCode.Value)
|
||||
}
|
||||
oa.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
oa.PropertyChanges = NewPropertyChanges(changes)
|
||||
return oa
|
||||
}
|
||||
|
||||
// OAuthFlowChanges represents an OpenAPI OAuthFlow object.
|
||||
type OAuthFlowChanges struct {
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between OAuthFlow objects
|
||||
func (o *OAuthFlowChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, o.Changes...)
|
||||
if o.ExtensionChanges != nil {
|
||||
changes = append(changes, o.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, o.Changes...)
|
||||
if o.ExtensionChanges != nil {
|
||||
changes = append(changes, o.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the total number of changes made between two OAuthFlow objects
|
||||
func (o *OAuthFlowChanges) TotalChanges() int {
|
||||
c := o.PropertyChanges.TotalChanges()
|
||||
if o.ExtensionChanges != nil {
|
||||
c += o.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := o.PropertyChanges.TotalChanges()
|
||||
if o.ExtensionChanges != nil {
|
||||
c += o.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the total number of breaking changes made between two OAuthFlow objects
|
||||
func (o *OAuthFlowChanges) TotalBreakingChanges() int {
|
||||
return o.PropertyChanges.TotalBreakingChanges()
|
||||
return o.PropertyChanges.TotalBreakingChanges()
|
||||
}
|
||||
|
||||
// CompareOAuthFlow checks a left and a right OAuthFlow object for changes. If found, returns a pointer to
|
||||
// an OAuthFlowChanges instance, or nil if nothing is found.
|
||||
func CompareOAuthFlow(l, r *v3.OAuthFlow) *OAuthFlowChanges {
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
|
||||
// authorization url
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.AuthorizationUrl.ValueNode,
|
||||
RightNode: r.AuthorizationUrl.ValueNode,
|
||||
Label: v3.AuthorizationUrlLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// authorization url
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.AuthorizationUrl.ValueNode,
|
||||
RightNode: r.AuthorizationUrl.ValueNode,
|
||||
Label: v3.AuthorizationUrlLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// token url
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.TokenUrl.ValueNode,
|
||||
RightNode: r.TokenUrl.ValueNode,
|
||||
Label: v3.TokenUrlLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// token url
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.TokenUrl.ValueNode,
|
||||
RightNode: r.TokenUrl.ValueNode,
|
||||
Label: v3.TokenUrlLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// refresh url
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.RefreshUrl.ValueNode,
|
||||
RightNode: r.RefreshUrl.ValueNode,
|
||||
Label: v3.RefreshUrlLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// refresh url
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.RefreshUrl.ValueNode,
|
||||
RightNode: r.RefreshUrl.ValueNode,
|
||||
Label: v3.RefreshUrlLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
CheckProperties(props)
|
||||
CheckProperties(props)
|
||||
|
||||
for v := range l.Scopes.Value {
|
||||
if r != nil && r.FindScope(v.Value) == nil {
|
||||
CreateChange(&changes, ObjectRemoved, v3.Scopes,
|
||||
l.Scopes.Value[v].ValueNode, nil, true,
|
||||
v.Value, nil)
|
||||
continue
|
||||
}
|
||||
if r != nil && r.FindScope(v.Value) != nil {
|
||||
if l.Scopes.Value[v].Value != r.FindScope(v.Value).Value {
|
||||
CreateChange(&changes, Modified, v3.Scopes,
|
||||
l.Scopes.Value[v].ValueNode, r.FindScope(v.Value).ValueNode, true,
|
||||
l.Scopes.Value[v].Value, r.FindScope(v.Value).Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
for v := range r.Scopes.Value {
|
||||
if l != nil && l.FindScope(v.Value) == nil {
|
||||
CreateChange(&changes, ObjectAdded, v3.Scopes,
|
||||
nil, r.Scopes.Value[v].ValueNode, false,
|
||||
nil, v.Value)
|
||||
}
|
||||
}
|
||||
oa := new(OAuthFlowChanges)
|
||||
oa.PropertyChanges = NewPropertyChanges(changes)
|
||||
oa.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
return oa
|
||||
for v := range l.Scopes.Value {
|
||||
if r != nil && r.FindScope(v.Value) == nil {
|
||||
CreateChange(&changes, ObjectRemoved, v3.Scopes,
|
||||
l.Scopes.Value[v].ValueNode, nil, true,
|
||||
v.Value, nil)
|
||||
continue
|
||||
}
|
||||
if r != nil && r.FindScope(v.Value) != nil {
|
||||
if l.Scopes.Value[v].Value != r.FindScope(v.Value).Value {
|
||||
CreateChange(&changes, Modified, v3.Scopes,
|
||||
l.Scopes.Value[v].ValueNode, r.FindScope(v.Value).ValueNode, true,
|
||||
l.Scopes.Value[v].Value, r.FindScope(v.Value).Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
for v := range r.Scopes.Value {
|
||||
if l != nil && l.FindScope(v.Value) == nil {
|
||||
CreateChange(&changes, ObjectAdded, v3.Scopes,
|
||||
nil, r.Scopes.Value[v].ValueNode, false,
|
||||
nil, v.Value)
|
||||
}
|
||||
}
|
||||
oa := new(OAuthFlowChanges)
|
||||
oa.PropertyChanges = NewPropertyChanges(changes)
|
||||
oa.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
return oa
|
||||
}
|
||||
|
||||
@@ -4,90 +4,90 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompareOAuthFlow(t *testing.T) {
|
||||
|
||||
left := `authorizationUrl: cheese
|
||||
left := `authorizationUrl: cheese
|
||||
tokenUrl: biscuits
|
||||
refreshUrl: cake
|
||||
scopes:
|
||||
riff: raff`
|
||||
|
||||
right := `authorizationUrl: cheese
|
||||
right := `authorizationUrl: cheese
|
||||
tokenUrl: biscuits
|
||||
refreshUrl: cake
|
||||
scopes:
|
||||
riff: raff`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlow
|
||||
var rDoc v3.OAuthFlow
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlow
|
||||
var rDoc v3.OAuthFlow
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare
|
||||
extChanges := CompareOAuthFlow(&lDoc, &rDoc)
|
||||
assert.Nil(t, extChanges)
|
||||
// compare
|
||||
extChanges := CompareOAuthFlow(&lDoc, &rDoc)
|
||||
assert.Nil(t, extChanges)
|
||||
|
||||
}
|
||||
|
||||
func TestCompareOAuthFlow_Modified(t *testing.T) {
|
||||
|
||||
left := `authorizationUrl: toast
|
||||
left := `authorizationUrl: toast
|
||||
tokenUrl: biscuits
|
||||
refreshUrl: roast
|
||||
scopes:
|
||||
riff: raff
|
||||
x-burgers: nice`
|
||||
|
||||
right := `authorizationUrl: cheese
|
||||
right := `authorizationUrl: cheese
|
||||
tokenUrl: biscuits
|
||||
refreshUrl: cake
|
||||
scopes:
|
||||
riff: raff
|
||||
x-burgers: crispy`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlow
|
||||
var rDoc v3.OAuthFlow
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlow
|
||||
var rDoc v3.OAuthFlow
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare
|
||||
extChanges := CompareOAuthFlow(&lDoc, &rDoc)
|
||||
assert.Equal(t, 3, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 3)
|
||||
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
|
||||
// compare
|
||||
extChanges := CompareOAuthFlow(&lDoc, &rDoc)
|
||||
assert.Equal(t, 3, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 3)
|
||||
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
|
||||
}
|
||||
|
||||
func TestCompareOAuthFlow_AddScope(t *testing.T) {
|
||||
|
||||
left := `authorizationUrl: toast
|
||||
left := `authorizationUrl: toast
|
||||
tokenUrl: biscuits
|
||||
refreshUrl: roast
|
||||
scopes:
|
||||
riff: raff
|
||||
x-burgers: nice`
|
||||
|
||||
right := `authorizationUrl: toast
|
||||
right := `authorizationUrl: toast
|
||||
tokenUrl: biscuits
|
||||
refreshUrl: roast
|
||||
scopes:
|
||||
@@ -95,37 +95,37 @@ scopes:
|
||||
tiff: taff
|
||||
x-burgers: nice`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlow
|
||||
var rDoc v3.OAuthFlow
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlow
|
||||
var rDoc v3.OAuthFlow
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare
|
||||
extChanges := CompareOAuthFlow(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, "taff", extChanges.Changes[0].New)
|
||||
assert.Equal(t, "tiff", extChanges.Changes[0].NewObject)
|
||||
// compare
|
||||
extChanges := CompareOAuthFlow(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, "taff", extChanges.Changes[0].New)
|
||||
assert.Equal(t, "tiff", extChanges.Changes[0].NewObject)
|
||||
}
|
||||
|
||||
func TestCompareOAuthFlow_RemoveScope(t *testing.T) {
|
||||
|
||||
left := `authorizationUrl: toast
|
||||
left := `authorizationUrl: toast
|
||||
tokenUrl: biscuits
|
||||
refreshUrl: roast
|
||||
scopes:
|
||||
riff: raff
|
||||
x-burgers: nice`
|
||||
|
||||
right := `authorizationUrl: toast
|
||||
right := `authorizationUrl: toast
|
||||
tokenUrl: biscuits
|
||||
refreshUrl: roast
|
||||
scopes:
|
||||
@@ -133,68 +133,68 @@ scopes:
|
||||
tiff: taff
|
||||
x-burgers: nice`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlow
|
||||
var rDoc v3.OAuthFlow
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlow
|
||||
var rDoc v3.OAuthFlow
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare
|
||||
extChanges := CompareOAuthFlow(&rDoc, &lDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, "taff", extChanges.Changes[0].Original)
|
||||
assert.Equal(t, "tiff", extChanges.Changes[0].OriginalObject)
|
||||
// compare
|
||||
extChanges := CompareOAuthFlow(&rDoc, &lDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, "taff", extChanges.Changes[0].Original)
|
||||
assert.Equal(t, "tiff", extChanges.Changes[0].OriginalObject)
|
||||
}
|
||||
|
||||
func TestCompareOAuthFlow_ModifyScope(t *testing.T) {
|
||||
|
||||
left := `authorizationUrl: toast
|
||||
left := `authorizationUrl: toast
|
||||
tokenUrl: biscuits
|
||||
refreshUrl: roast
|
||||
scopes:
|
||||
riff: ruffles
|
||||
x-burgers: nice`
|
||||
|
||||
right := `authorizationUrl: toast
|
||||
right := `authorizationUrl: toast
|
||||
tokenUrl: biscuits
|
||||
refreshUrl: roast
|
||||
scopes:
|
||||
riff: raff
|
||||
x-burgers: nice`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlow
|
||||
var rDoc v3.OAuthFlow
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlow
|
||||
var rDoc v3.OAuthFlow
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare
|
||||
extChanges := CompareOAuthFlow(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, "raff", extChanges.Changes[0].New)
|
||||
assert.Equal(t, "raff", extChanges.Changes[0].NewObject)
|
||||
assert.Equal(t, "ruffles", extChanges.Changes[0].Original)
|
||||
assert.Equal(t, "ruffles", extChanges.Changes[0].OriginalObject)
|
||||
// compare
|
||||
extChanges := CompareOAuthFlow(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, "raff", extChanges.Changes[0].New)
|
||||
assert.Equal(t, "raff", extChanges.Changes[0].NewObject)
|
||||
assert.Equal(t, "ruffles", extChanges.Changes[0].Original)
|
||||
assert.Equal(t, "ruffles", extChanges.Changes[0].OriginalObject)
|
||||
}
|
||||
|
||||
func TestCompareOAuthFlows(t *testing.T) {
|
||||
left := `implicit:
|
||||
left := `implicit:
|
||||
authorizationUrl: cheese
|
||||
password:
|
||||
authorizationUrl: cake
|
||||
@@ -204,7 +204,7 @@ authorizationCode:
|
||||
authorizationUrl: chalk
|
||||
x-coke: cola`
|
||||
|
||||
right := `implicit:
|
||||
right := `implicit:
|
||||
authorizationUrl: cheese
|
||||
password:
|
||||
authorizationUrl: cake
|
||||
@@ -214,27 +214,27 @@ authorizationCode:
|
||||
authorizationUrl: chalk
|
||||
x-coke: cola`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlows
|
||||
var rDoc v3.OAuthFlows
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlows
|
||||
var rDoc v3.OAuthFlows
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare
|
||||
extChanges := CompareOAuthFlows(&lDoc, &rDoc)
|
||||
assert.Nil(t, extChanges)
|
||||
// compare
|
||||
extChanges := CompareOAuthFlows(&lDoc, &rDoc)
|
||||
assert.Nil(t, extChanges)
|
||||
}
|
||||
|
||||
func TestCompareOAuthFlows_AddEverything(t *testing.T) {
|
||||
left := `x-coke: cola`
|
||||
left := `x-coke: cola`
|
||||
|
||||
right := `implicit:
|
||||
right := `implicit:
|
||||
authorizationUrl: cheese
|
||||
password:
|
||||
authorizationUrl: cake
|
||||
@@ -244,29 +244,29 @@ authorizationCode:
|
||||
authorizationUrl: chalk
|
||||
x-coke: cola`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlows
|
||||
var rDoc v3.OAuthFlows
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlows
|
||||
var rDoc v3.OAuthFlows
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare
|
||||
extChanges := CompareOAuthFlows(&lDoc, &rDoc)
|
||||
assert.Equal(t, 4, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 4)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
// compare
|
||||
extChanges := CompareOAuthFlows(&lDoc, &rDoc)
|
||||
assert.Equal(t, 4, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 4)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
}
|
||||
|
||||
func TestCompareOAuthFlows_RemoveEverything(t *testing.T) {
|
||||
left := `x-coke: cola`
|
||||
left := `x-coke: cola`
|
||||
|
||||
right := `implicit:
|
||||
right := `implicit:
|
||||
authorizationUrl: cheese
|
||||
password:
|
||||
authorizationUrl: cake
|
||||
@@ -276,27 +276,27 @@ authorizationCode:
|
||||
authorizationUrl: chalk
|
||||
x-coke: cola`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlows
|
||||
var rDoc v3.OAuthFlows
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlows
|
||||
var rDoc v3.OAuthFlows
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare
|
||||
extChanges := CompareOAuthFlows(&rDoc, &lDoc)
|
||||
assert.Equal(t, 4, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 4)
|
||||
assert.Equal(t, 4, extChanges.TotalBreakingChanges())
|
||||
// compare
|
||||
extChanges := CompareOAuthFlows(&rDoc, &lDoc)
|
||||
assert.Equal(t, 4, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 4)
|
||||
assert.Equal(t, 4, extChanges.TotalBreakingChanges())
|
||||
}
|
||||
|
||||
func TestCompareOAuthFlows_ModifyEverything(t *testing.T) {
|
||||
left := `implicit:
|
||||
left := `implicit:
|
||||
authorizationUrl: cheese
|
||||
password:
|
||||
authorizationUrl: cake
|
||||
@@ -306,7 +306,7 @@ authorizationCode:
|
||||
authorizationUrl: chalk
|
||||
x-coke: cola`
|
||||
|
||||
right := `implicit:
|
||||
right := `implicit:
|
||||
authorizationUrl: herbs
|
||||
password:
|
||||
authorizationUrl: coffee
|
||||
@@ -316,21 +316,21 @@ authorizationCode:
|
||||
authorizationUrl: pasta
|
||||
x-coke: cherry`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlows
|
||||
var rDoc v3.OAuthFlows
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.OAuthFlows
|
||||
var rDoc v3.OAuthFlows
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare
|
||||
extChanges := CompareOAuthFlows(&lDoc, &rDoc)
|
||||
assert.Equal(t, 5, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 5)
|
||||
assert.Equal(t, 4, extChanges.TotalBreakingChanges())
|
||||
// compare
|
||||
extChanges := CompareOAuthFlows(&lDoc, &rDoc)
|
||||
assert.Equal(t, 5, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 5)
|
||||
assert.Equal(t, 4, extChanges.TotalBreakingChanges())
|
||||
}
|
||||
|
||||
@@ -4,351 +4,351 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"gopkg.in/yaml.v3"
|
||||
"reflect"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"gopkg.in/yaml.v3"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// ParameterChanges represents changes found between Swagger or OpenAPI Parameter objects.
|
||||
type ParameterChanges struct {
|
||||
*PropertyChanges
|
||||
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
*PropertyChanges
|
||||
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
|
||||
// Swagger supports Items.
|
||||
ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
// Swagger supports Items.
|
||||
ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
|
||||
// OpenAPI supports examples and content types.
|
||||
ExamplesChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
// OpenAPI supports examples and content types.
|
||||
ExamplesChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Parameter objects
|
||||
func (p *ParameterChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, p.Changes...)
|
||||
if p.SchemaChanges != nil {
|
||||
changes = append(changes, p.SchemaChanges.GetAllChanges()...)
|
||||
}
|
||||
for i := range p.ExamplesChanges {
|
||||
changes = append(changes, p.ExamplesChanges[i].GetAllChanges()...)
|
||||
}
|
||||
if p.ItemsChanges != nil {
|
||||
changes = append(changes, p.ItemsChanges.GetAllChanges()...)
|
||||
}
|
||||
if p.ExtensionChanges != nil {
|
||||
changes = append(changes, p.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
for i := range p.ContentChanges {
|
||||
changes = append(changes, p.ContentChanges[i].GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, p.Changes...)
|
||||
if p.SchemaChanges != nil {
|
||||
changes = append(changes, p.SchemaChanges.GetAllChanges()...)
|
||||
}
|
||||
for i := range p.ExamplesChanges {
|
||||
changes = append(changes, p.ExamplesChanges[i].GetAllChanges()...)
|
||||
}
|
||||
if p.ItemsChanges != nil {
|
||||
changes = append(changes, p.ItemsChanges.GetAllChanges()...)
|
||||
}
|
||||
if p.ExtensionChanges != nil {
|
||||
changes = append(changes, p.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
for i := range p.ContentChanges {
|
||||
changes = append(changes, p.ContentChanges[i].GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns a count of everything that changed
|
||||
func (p *ParameterChanges) TotalChanges() int {
|
||||
c := p.PropertyChanges.TotalChanges()
|
||||
if p.SchemaChanges != nil {
|
||||
c += p.SchemaChanges.TotalChanges()
|
||||
}
|
||||
for i := range p.ExamplesChanges {
|
||||
c += p.ExamplesChanges[i].TotalChanges()
|
||||
}
|
||||
if p.ItemsChanges != nil {
|
||||
c += p.ItemsChanges.TotalChanges()
|
||||
}
|
||||
if p.ExtensionChanges != nil {
|
||||
c += p.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
for i := range p.ContentChanges {
|
||||
c += p.ContentChanges[i].TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := p.PropertyChanges.TotalChanges()
|
||||
if p.SchemaChanges != nil {
|
||||
c += p.SchemaChanges.TotalChanges()
|
||||
}
|
||||
for i := range p.ExamplesChanges {
|
||||
c += p.ExamplesChanges[i].TotalChanges()
|
||||
}
|
||||
if p.ItemsChanges != nil {
|
||||
c += p.ItemsChanges.TotalChanges()
|
||||
}
|
||||
if p.ExtensionChanges != nil {
|
||||
c += p.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
for i := range p.ContentChanges {
|
||||
c += p.ContentChanges[i].TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges always returns 0 for ExternalDoc objects, they are non-binding.
|
||||
func (p *ParameterChanges) TotalBreakingChanges() int {
|
||||
c := p.PropertyChanges.TotalBreakingChanges()
|
||||
if p.SchemaChanges != nil {
|
||||
c += p.SchemaChanges.TotalBreakingChanges()
|
||||
}
|
||||
if p.ItemsChanges != nil {
|
||||
c += p.ItemsChanges.TotalBreakingChanges()
|
||||
}
|
||||
for i := range p.ContentChanges {
|
||||
c += p.ContentChanges[i].TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
c := p.PropertyChanges.TotalBreakingChanges()
|
||||
if p.SchemaChanges != nil {
|
||||
c += p.SchemaChanges.TotalBreakingChanges()
|
||||
}
|
||||
if p.ItemsChanges != nil {
|
||||
c += p.ItemsChanges.TotalBreakingChanges()
|
||||
}
|
||||
for i := range p.ContentChanges {
|
||||
c += p.ContentChanges[i].TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func addPropertyCheck(props *[]*PropertyCheck,
|
||||
lvn, rvn *yaml.Node, lv, rv any, changes *[]*Change, label string, breaking bool) {
|
||||
*props = append(*props, &PropertyCheck{
|
||||
LeftNode: lvn,
|
||||
RightNode: rvn,
|
||||
Label: label,
|
||||
Changes: changes,
|
||||
Breaking: breaking,
|
||||
Original: lv,
|
||||
New: rv,
|
||||
})
|
||||
lvn, rvn *yaml.Node, lv, rv any, changes *[]*Change, label string, breaking bool) {
|
||||
*props = append(*props, &PropertyCheck{
|
||||
LeftNode: lvn,
|
||||
RightNode: rvn,
|
||||
Label: label,
|
||||
Changes: changes,
|
||||
Breaking: breaking,
|
||||
Original: lv,
|
||||
New: rv,
|
||||
})
|
||||
}
|
||||
|
||||
func addOpenAPIParameterProperties(left, right low.OpenAPIParameter, changes *[]*Change) []*PropertyCheck {
|
||||
var props []*PropertyCheck
|
||||
var props []*PropertyCheck
|
||||
|
||||
// style
|
||||
addPropertyCheck(&props, left.GetStyle().ValueNode, right.GetStyle().ValueNode,
|
||||
left.GetStyle(), right.GetStyle(), changes, v3.StyleLabel, false)
|
||||
// style
|
||||
addPropertyCheck(&props, left.GetStyle().ValueNode, right.GetStyle().ValueNode,
|
||||
left.GetStyle(), right.GetStyle(), changes, v3.StyleLabel, false)
|
||||
|
||||
// allow reserved
|
||||
addPropertyCheck(&props, left.GetAllowReserved().ValueNode, right.GetAllowReserved().ValueNode,
|
||||
left.GetAllowReserved(), right.GetAllowReserved(), changes, v3.AllowReservedLabel, true)
|
||||
// allow reserved
|
||||
addPropertyCheck(&props, left.GetAllowReserved().ValueNode, right.GetAllowReserved().ValueNode,
|
||||
left.GetAllowReserved(), right.GetAllowReserved(), changes, v3.AllowReservedLabel, true)
|
||||
|
||||
// explode
|
||||
addPropertyCheck(&props, left.GetExplode().ValueNode, right.GetExplode().ValueNode,
|
||||
left.GetExplode(), right.GetExplode(), changes, v3.ExplodeLabel, false)
|
||||
// explode
|
||||
addPropertyCheck(&props, left.GetExplode().ValueNode, right.GetExplode().ValueNode,
|
||||
left.GetExplode(), right.GetExplode(), changes, v3.ExplodeLabel, false)
|
||||
|
||||
// deprecated
|
||||
addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode,
|
||||
left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false)
|
||||
// deprecated
|
||||
addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode,
|
||||
left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false)
|
||||
|
||||
// example
|
||||
addPropertyCheck(&props, left.GetExample().ValueNode, right.GetExample().ValueNode,
|
||||
left.GetExample(), right.GetExample(), changes, v3.ExampleLabel, false)
|
||||
// example
|
||||
addPropertyCheck(&props, left.GetExample().ValueNode, right.GetExample().ValueNode,
|
||||
left.GetExample(), right.GetExample(), changes, v3.ExampleLabel, false)
|
||||
|
||||
return props
|
||||
return props
|
||||
}
|
||||
|
||||
func addSwaggerParameterProperties(left, right low.SwaggerParameter, changes *[]*Change) []*PropertyCheck {
|
||||
var props []*PropertyCheck
|
||||
var props []*PropertyCheck
|
||||
|
||||
// type
|
||||
addPropertyCheck(&props, left.GetType().ValueNode, right.GetType().ValueNode,
|
||||
left.GetType(), right.GetType(), changes, v3.TypeLabel, true)
|
||||
// type
|
||||
addPropertyCheck(&props, left.GetType().ValueNode, right.GetType().ValueNode,
|
||||
left.GetType(), right.GetType(), changes, v3.TypeLabel, true)
|
||||
|
||||
// format
|
||||
addPropertyCheck(&props, left.GetFormat().ValueNode, right.GetFormat().ValueNode,
|
||||
left.GetFormat(), right.GetFormat(), changes, v3.FormatLabel, true)
|
||||
// format
|
||||
addPropertyCheck(&props, left.GetFormat().ValueNode, right.GetFormat().ValueNode,
|
||||
left.GetFormat(), right.GetFormat(), changes, v3.FormatLabel, true)
|
||||
|
||||
// collection format
|
||||
addPropertyCheck(&props, left.GetCollectionFormat().ValueNode, right.GetCollectionFormat().ValueNode,
|
||||
left.GetCollectionFormat(), right.GetCollectionFormat(), changes, v3.CollectionFormatLabel, true)
|
||||
// collection format
|
||||
addPropertyCheck(&props, left.GetCollectionFormat().ValueNode, right.GetCollectionFormat().ValueNode,
|
||||
left.GetCollectionFormat(), right.GetCollectionFormat(), changes, v3.CollectionFormatLabel, true)
|
||||
|
||||
// maximum
|
||||
addPropertyCheck(&props, left.GetMaximum().ValueNode, right.GetMaximum().ValueNode,
|
||||
left.GetMaximum(), right.GetMaximum(), changes, v3.MaximumLabel, true)
|
||||
// maximum
|
||||
addPropertyCheck(&props, left.GetMaximum().ValueNode, right.GetMaximum().ValueNode,
|
||||
left.GetMaximum(), right.GetMaximum(), changes, v3.MaximumLabel, true)
|
||||
|
||||
// minimum
|
||||
addPropertyCheck(&props, left.GetMinimum().ValueNode, right.GetMinimum().ValueNode,
|
||||
left.GetMinimum(), right.GetMinimum(), changes, v3.MinimumLabel, true)
|
||||
// minimum
|
||||
addPropertyCheck(&props, left.GetMinimum().ValueNode, right.GetMinimum().ValueNode,
|
||||
left.GetMinimum(), right.GetMinimum(), changes, v3.MinimumLabel, true)
|
||||
|
||||
// exclusive maximum
|
||||
addPropertyCheck(&props, left.GetExclusiveMaximum().ValueNode, right.GetExclusiveMaximum().ValueNode,
|
||||
left.GetExclusiveMaximum(), right.GetExclusiveMaximum(), changes, v3.ExclusiveMaximumLabel, true)
|
||||
// exclusive maximum
|
||||
addPropertyCheck(&props, left.GetExclusiveMaximum().ValueNode, right.GetExclusiveMaximum().ValueNode,
|
||||
left.GetExclusiveMaximum(), right.GetExclusiveMaximum(), changes, v3.ExclusiveMaximumLabel, true)
|
||||
|
||||
// exclusive minimum
|
||||
addPropertyCheck(&props, left.GetExclusiveMinimum().ValueNode, right.GetExclusiveMinimum().ValueNode,
|
||||
left.GetExclusiveMinimum(), right.GetExclusiveMinimum(), changes, v3.ExclusiveMinimumLabel, true)
|
||||
// exclusive minimum
|
||||
addPropertyCheck(&props, left.GetExclusiveMinimum().ValueNode, right.GetExclusiveMinimum().ValueNode,
|
||||
left.GetExclusiveMinimum(), right.GetExclusiveMinimum(), changes, v3.ExclusiveMinimumLabel, true)
|
||||
|
||||
// max length
|
||||
addPropertyCheck(&props, left.GetMaxLength().ValueNode, right.GetMaxLength().ValueNode,
|
||||
left.GetMaxLength(), right.GetMaxLength(), changes, v3.MaxLengthLabel, true)
|
||||
// max length
|
||||
addPropertyCheck(&props, left.GetMaxLength().ValueNode, right.GetMaxLength().ValueNode,
|
||||
left.GetMaxLength(), right.GetMaxLength(), changes, v3.MaxLengthLabel, true)
|
||||
|
||||
// min length
|
||||
addPropertyCheck(&props, left.GetMinLength().ValueNode, right.GetMinLength().ValueNode,
|
||||
left.GetMinLength(), right.GetMinLength(), changes, v3.MinLengthLabel, true)
|
||||
// min length
|
||||
addPropertyCheck(&props, left.GetMinLength().ValueNode, right.GetMinLength().ValueNode,
|
||||
left.GetMinLength(), right.GetMinLength(), changes, v3.MinLengthLabel, true)
|
||||
|
||||
// pattern
|
||||
addPropertyCheck(&props, left.GetPattern().ValueNode, right.GetPattern().ValueNode,
|
||||
left.GetPattern(), right.GetPattern(), changes, v3.PatternLabel, true)
|
||||
// pattern
|
||||
addPropertyCheck(&props, left.GetPattern().ValueNode, right.GetPattern().ValueNode,
|
||||
left.GetPattern(), right.GetPattern(), changes, v3.PatternLabel, true)
|
||||
|
||||
// max items
|
||||
addPropertyCheck(&props, left.GetMaxItems().ValueNode, right.GetMaxItems().ValueNode,
|
||||
left.GetMaxItems(), right.GetMaxItems(), changes, v3.MaxItemsLabel, true)
|
||||
// max items
|
||||
addPropertyCheck(&props, left.GetMaxItems().ValueNode, right.GetMaxItems().ValueNode,
|
||||
left.GetMaxItems(), right.GetMaxItems(), changes, v3.MaxItemsLabel, true)
|
||||
|
||||
// min items
|
||||
addPropertyCheck(&props, left.GetMinItems().ValueNode, right.GetMinItems().ValueNode,
|
||||
left.GetMinItems(), right.GetMinItems(), changes, v3.MinItemsLabel, true)
|
||||
// min items
|
||||
addPropertyCheck(&props, left.GetMinItems().ValueNode, right.GetMinItems().ValueNode,
|
||||
left.GetMinItems(), right.GetMinItems(), changes, v3.MinItemsLabel, true)
|
||||
|
||||
// unique items
|
||||
addPropertyCheck(&props, left.GetUniqueItems().ValueNode, right.GetUniqueItems().ValueNode,
|
||||
left.GetUniqueItems(), right.GetUniqueItems(), changes, v3.UniqueItemsLabel, true)
|
||||
// unique items
|
||||
addPropertyCheck(&props, left.GetUniqueItems().ValueNode, right.GetUniqueItems().ValueNode,
|
||||
left.GetUniqueItems(), right.GetUniqueItems(), changes, v3.UniqueItemsLabel, true)
|
||||
|
||||
// default
|
||||
addPropertyCheck(&props, left.GetDefault().ValueNode, right.GetDefault().ValueNode,
|
||||
left.GetDefault(), right.GetDefault(), changes, v3.DefaultLabel, true)
|
||||
// default
|
||||
addPropertyCheck(&props, left.GetDefault().ValueNode, right.GetDefault().ValueNode,
|
||||
left.GetDefault(), right.GetDefault(), changes, v3.DefaultLabel, true)
|
||||
|
||||
// multiple of
|
||||
addPropertyCheck(&props, left.GetMultipleOf().ValueNode, right.GetMultipleOf().ValueNode,
|
||||
left.GetMultipleOf(), right.GetMultipleOf(), changes, v3.MultipleOfLabel, true)
|
||||
// multiple of
|
||||
addPropertyCheck(&props, left.GetMultipleOf().ValueNode, right.GetMultipleOf().ValueNode,
|
||||
left.GetMultipleOf(), right.GetMultipleOf(), changes, v3.MultipleOfLabel, true)
|
||||
|
||||
return props
|
||||
return props
|
||||
}
|
||||
|
||||
func addCommonParameterProperties(left, right low.SharedParameters, changes *[]*Change) []*PropertyCheck {
|
||||
var props []*PropertyCheck
|
||||
var props []*PropertyCheck
|
||||
|
||||
addPropertyCheck(&props, left.GetName().ValueNode, right.GetName().ValueNode,
|
||||
left.GetName(), right.GetName(), changes, v3.NameLabel, true)
|
||||
addPropertyCheck(&props, left.GetName().ValueNode, right.GetName().ValueNode,
|
||||
left.GetName(), right.GetName(), changes, v3.NameLabel, true)
|
||||
|
||||
// in
|
||||
addPropertyCheck(&props, left.GetIn().ValueNode, right.GetIn().ValueNode,
|
||||
left.GetIn(), right.GetIn(), changes, v3.InLabel, true)
|
||||
// in
|
||||
addPropertyCheck(&props, left.GetIn().ValueNode, right.GetIn().ValueNode,
|
||||
left.GetIn(), right.GetIn(), changes, v3.InLabel, true)
|
||||
|
||||
// description
|
||||
addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode,
|
||||
left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false)
|
||||
// description
|
||||
addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode,
|
||||
left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false)
|
||||
|
||||
// required
|
||||
addPropertyCheck(&props, left.GetRequired().ValueNode, right.GetRequired().ValueNode,
|
||||
left.GetRequired(), right.GetRequired(), changes, v3.RequiredLabel, true)
|
||||
// required
|
||||
addPropertyCheck(&props, left.GetRequired().ValueNode, right.GetRequired().ValueNode,
|
||||
left.GetRequired(), right.GetRequired(), changes, v3.RequiredLabel, true)
|
||||
|
||||
// allow empty value
|
||||
addPropertyCheck(&props, left.GetAllowEmptyValue().ValueNode, right.GetAllowEmptyValue().ValueNode,
|
||||
left.GetAllowEmptyValue(), right.GetAllowEmptyValue(), changes, v3.AllowEmptyValueLabel, true)
|
||||
// allow empty value
|
||||
addPropertyCheck(&props, left.GetAllowEmptyValue().ValueNode, right.GetAllowEmptyValue().ValueNode,
|
||||
left.GetAllowEmptyValue(), right.GetAllowEmptyValue(), changes, v3.AllowEmptyValueLabel, true)
|
||||
|
||||
return props
|
||||
return props
|
||||
}
|
||||
|
||||
// CompareParametersV3 is an OpenAPI type safe proxy for CompareParameters
|
||||
func CompareParametersV3(l, r *v3.Parameter) *ParameterChanges {
|
||||
return CompareParameters(l, r)
|
||||
return CompareParameters(l, r)
|
||||
}
|
||||
|
||||
// CompareParameters compares a left and right Swagger or OpenAPI Parameter object for any changes. If found returns
|
||||
// a pointer to ParameterChanges. If nothing is found, returns nil.
|
||||
func CompareParameters(l, r any) *ParameterChanges {
|
||||
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
|
||||
pc := new(ParameterChanges)
|
||||
var lSchema *base.SchemaProxy
|
||||
var rSchema *base.SchemaProxy
|
||||
var lext, rext map[low.KeyReference[string]]low.ValueReference[any]
|
||||
pc := new(ParameterChanges)
|
||||
var lSchema *base.SchemaProxy
|
||||
var rSchema *base.SchemaProxy
|
||||
var lext, rext map[low.KeyReference[string]]low.ValueReference[any]
|
||||
|
||||
if reflect.TypeOf(&v2.Parameter{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Parameter{}) == reflect.TypeOf(r) {
|
||||
lParam := l.(*v2.Parameter)
|
||||
rParam := r.(*v2.Parameter)
|
||||
if reflect.TypeOf(&v2.Parameter{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Parameter{}) == reflect.TypeOf(r) {
|
||||
lParam := l.(*v2.Parameter)
|
||||
rParam := r.(*v2.Parameter)
|
||||
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lParam, rParam) {
|
||||
return nil
|
||||
}
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lParam, rParam) {
|
||||
return nil
|
||||
}
|
||||
|
||||
props = append(props, addSwaggerParameterProperties(lParam, rParam, &changes)...)
|
||||
props = append(props, addCommonParameterProperties(lParam, rParam, &changes)...)
|
||||
props = append(props, addSwaggerParameterProperties(lParam, rParam, &changes)...)
|
||||
props = append(props, addCommonParameterProperties(lParam, rParam, &changes)...)
|
||||
|
||||
// extract schema
|
||||
if lParam != nil {
|
||||
lSchema = lParam.Schema.Value
|
||||
lext = lParam.Extensions
|
||||
}
|
||||
if rParam != nil {
|
||||
rext = rParam.Extensions
|
||||
rSchema = rParam.Schema.Value
|
||||
}
|
||||
// extract schema
|
||||
if lParam != nil {
|
||||
lSchema = lParam.Schema.Value
|
||||
lext = lParam.Extensions
|
||||
}
|
||||
if rParam != nil {
|
||||
rext = rParam.Extensions
|
||||
rSchema = rParam.Schema.Value
|
||||
}
|
||||
|
||||
// items
|
||||
if !lParam.Items.IsEmpty() && !rParam.Items.IsEmpty() {
|
||||
if lParam.Items.Value.Hash() != rParam.Items.Value.Hash() {
|
||||
pc.ItemsChanges = CompareItems(lParam.Items.Value, rParam.Items.Value)
|
||||
}
|
||||
}
|
||||
if lParam.Items.IsEmpty() && !rParam.Items.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.ItemsLabel,
|
||||
nil, rParam.Items.ValueNode, true, nil,
|
||||
rParam.Items.Value)
|
||||
}
|
||||
if !lParam.Items.IsEmpty() && rParam.Items.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.ItemsLabel,
|
||||
lParam.Items.ValueNode, nil, true, lParam.Items.Value,
|
||||
nil)
|
||||
}
|
||||
// items
|
||||
if !lParam.Items.IsEmpty() && !rParam.Items.IsEmpty() {
|
||||
if lParam.Items.Value.Hash() != rParam.Items.Value.Hash() {
|
||||
pc.ItemsChanges = CompareItems(lParam.Items.Value, rParam.Items.Value)
|
||||
}
|
||||
}
|
||||
if lParam.Items.IsEmpty() && !rParam.Items.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.ItemsLabel,
|
||||
nil, rParam.Items.ValueNode, true, nil,
|
||||
rParam.Items.Value)
|
||||
}
|
||||
if !lParam.Items.IsEmpty() && rParam.Items.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.ItemsLabel,
|
||||
lParam.Items.ValueNode, nil, true, lParam.Items.Value,
|
||||
nil)
|
||||
}
|
||||
|
||||
// enum
|
||||
if len(lParam.Enum.Value) > 0 || len(rParam.Enum.Value) > 0 {
|
||||
ExtractRawValueSliceChanges(lParam.Enum.Value, rParam.Enum.Value, &changes, v3.EnumLabel, true)
|
||||
}
|
||||
}
|
||||
// enum
|
||||
if len(lParam.Enum.Value) > 0 || len(rParam.Enum.Value) > 0 {
|
||||
ExtractRawValueSliceChanges(lParam.Enum.Value, rParam.Enum.Value, &changes, v3.EnumLabel, true)
|
||||
}
|
||||
}
|
||||
|
||||
// OpenAPI
|
||||
if reflect.TypeOf(&v3.Parameter{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Parameter{}) == reflect.TypeOf(r) {
|
||||
// OpenAPI
|
||||
if reflect.TypeOf(&v3.Parameter{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Parameter{}) == reflect.TypeOf(r) {
|
||||
|
||||
lParam := l.(*v3.Parameter)
|
||||
rParam := r.(*v3.Parameter)
|
||||
lParam := l.(*v3.Parameter)
|
||||
rParam := r.(*v3.Parameter)
|
||||
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lParam, rParam) {
|
||||
return nil
|
||||
}
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lParam, rParam) {
|
||||
return nil
|
||||
}
|
||||
|
||||
props = append(props, addOpenAPIParameterProperties(lParam, rParam, &changes)...)
|
||||
props = append(props, addCommonParameterProperties(lParam, rParam, &changes)...)
|
||||
if lParam != nil {
|
||||
lext = lParam.Extensions
|
||||
lSchema = lParam.Schema.Value
|
||||
}
|
||||
if rParam != nil {
|
||||
rext = rParam.Extensions
|
||||
rSchema = rParam.Schema.Value
|
||||
}
|
||||
props = append(props, addOpenAPIParameterProperties(lParam, rParam, &changes)...)
|
||||
props = append(props, addCommonParameterProperties(lParam, rParam, &changes)...)
|
||||
if lParam != nil {
|
||||
lext = lParam.Extensions
|
||||
lSchema = lParam.Schema.Value
|
||||
}
|
||||
if rParam != nil {
|
||||
rext = rParam.Extensions
|
||||
rSchema = rParam.Schema.Value
|
||||
}
|
||||
|
||||
// example
|
||||
checkParameterExample(lParam.Example, rParam.Example, changes)
|
||||
// example
|
||||
checkParameterExample(lParam.Example, rParam.Example, changes)
|
||||
|
||||
// examples
|
||||
pc.ExamplesChanges = CheckMapForChanges(lParam.Examples.Value, rParam.Examples.Value,
|
||||
&changes, v3.ExamplesLabel, CompareExamples)
|
||||
// examples
|
||||
pc.ExamplesChanges = CheckMapForChanges(lParam.Examples.Value, rParam.Examples.Value,
|
||||
&changes, v3.ExamplesLabel, CompareExamples)
|
||||
|
||||
// content
|
||||
pc.ContentChanges = CheckMapForChanges(lParam.Content.Value, rParam.Content.Value,
|
||||
&changes, v3.ContentLabel, CompareMediaTypes)
|
||||
}
|
||||
CheckProperties(props)
|
||||
// content
|
||||
pc.ContentChanges = CheckMapForChanges(lParam.Content.Value, rParam.Content.Value,
|
||||
&changes, v3.ContentLabel, CompareMediaTypes)
|
||||
}
|
||||
CheckProperties(props)
|
||||
|
||||
if lSchema != nil && rSchema != nil {
|
||||
pc.SchemaChanges = CompareSchemas(lSchema, rSchema)
|
||||
}
|
||||
if lSchema != nil && rSchema == nil {
|
||||
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel,
|
||||
lSchema.GetValueNode(), nil, true, lSchema,
|
||||
nil)
|
||||
}
|
||||
if lSchema != nil && rSchema != nil {
|
||||
pc.SchemaChanges = CompareSchemas(lSchema, rSchema)
|
||||
}
|
||||
if lSchema != nil && rSchema == nil {
|
||||
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel,
|
||||
lSchema.GetValueNode(), nil, true, lSchema,
|
||||
nil)
|
||||
}
|
||||
|
||||
if lSchema == nil && rSchema != nil {
|
||||
CreateChange(&changes, ObjectAdded, v3.SchemaLabel,
|
||||
nil, rSchema.GetValueNode(), true, nil,
|
||||
rSchema)
|
||||
}
|
||||
if lSchema == nil && rSchema != nil {
|
||||
CreateChange(&changes, ObjectAdded, v3.SchemaLabel,
|
||||
nil, rSchema.GetValueNode(), true, nil,
|
||||
rSchema)
|
||||
}
|
||||
|
||||
pc.PropertyChanges = NewPropertyChanges(changes)
|
||||
pc.ExtensionChanges = CompareExtensions(lext, rext)
|
||||
return pc
|
||||
pc.PropertyChanges = NewPropertyChanges(changes)
|
||||
pc.ExtensionChanges = CompareExtensions(lext, rext)
|
||||
return pc
|
||||
}
|
||||
|
||||
func checkParameterExample(expLeft, expRight low.NodeReference[any], changes []*Change) {
|
||||
if !expLeft.IsEmpty() && !expRight.IsEmpty() {
|
||||
if low.GenerateHashString(expLeft.GetValue()) != low.GenerateHashString(expRight.GetValue()) {
|
||||
CreateChange(&changes, Modified, v3.ExampleLabel,
|
||||
expLeft.GetValueNode(), expRight.GetValueNode(), false,
|
||||
expLeft.GetValue(), expRight.GetValue())
|
||||
}
|
||||
}
|
||||
if expLeft.Value == nil && expRight.Value != nil {
|
||||
CreateChange(&changes, PropertyAdded, v3.ExampleLabel,
|
||||
nil, expRight.GetValueNode(), false,
|
||||
nil, expRight.GetValue())
|
||||
if !expLeft.IsEmpty() && !expRight.IsEmpty() {
|
||||
if low.GenerateHashString(expLeft.GetValue()) != low.GenerateHashString(expRight.GetValue()) {
|
||||
CreateChange(&changes, Modified, v3.ExampleLabel,
|
||||
expLeft.GetValueNode(), expRight.GetValueNode(), false,
|
||||
expLeft.GetValue(), expRight.GetValue())
|
||||
}
|
||||
}
|
||||
if expLeft.Value == nil && expRight.Value != nil {
|
||||
CreateChange(&changes, PropertyAdded, v3.ExampleLabel,
|
||||
nil, expRight.GetValueNode(), false,
|
||||
nil, expRight.GetValue())
|
||||
|
||||
}
|
||||
if expLeft.Value != nil && expRight.Value == nil {
|
||||
CreateChange(&changes, PropertyRemoved, v3.ExampleLabel,
|
||||
expLeft.GetValueNode(), nil, false,
|
||||
expLeft.GetValue(), nil)
|
||||
}
|
||||
if expLeft.Value != nil && expRight.Value == nil {
|
||||
CreateChange(&changes, PropertyRemoved, v3.ExampleLabel,
|
||||
expLeft.GetValueNode(), nil, false,
|
||||
expLeft.GetValue(), nil)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,203 +4,203 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"reflect"
|
||||
"sync"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// PathsChanges represents changes found between two Swagger or OpenAPI Paths Objects.
|
||||
type PathsChanges struct {
|
||||
*PropertyChanges
|
||||
PathItemsChanges map[string]*PathItemChanges `json:"pathItems,omitempty" yaml:"pathItems,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
*PropertyChanges
|
||||
PathItemsChanges map[string]*PathItemChanges `json:"pathItems,omitempty" yaml:"pathItems,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Paths objects
|
||||
func (p *PathsChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, p.Changes...)
|
||||
for k := range p.PathItemsChanges {
|
||||
changes = append(changes, p.PathItemsChanges[k].GetAllChanges()...)
|
||||
}
|
||||
if p.ExtensionChanges != nil {
|
||||
changes = append(changes, p.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, p.Changes...)
|
||||
for k := range p.PathItemsChanges {
|
||||
changes = append(changes, p.PathItemsChanges[k].GetAllChanges()...)
|
||||
}
|
||||
if p.ExtensionChanges != nil {
|
||||
changes = append(changes, p.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the total number of changes between two Swagger or OpenAPI Paths Objects
|
||||
func (p *PathsChanges) TotalChanges() int {
|
||||
c := p.PropertyChanges.TotalChanges()
|
||||
for k := range p.PathItemsChanges {
|
||||
c += p.PathItemsChanges[k].TotalChanges()
|
||||
}
|
||||
if p.ExtensionChanges != nil {
|
||||
c += p.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := p.PropertyChanges.TotalChanges()
|
||||
for k := range p.PathItemsChanges {
|
||||
c += p.PathItemsChanges[k].TotalChanges()
|
||||
}
|
||||
if p.ExtensionChanges != nil {
|
||||
c += p.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns tht total number of changes found between two Swagger or OpenAPI Path Objects
|
||||
func (p *PathsChanges) TotalBreakingChanges() int {
|
||||
c := p.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range p.PathItemsChanges {
|
||||
c += p.PathItemsChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
c := p.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range p.PathItemsChanges {
|
||||
c += p.PathItemsChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// ComparePaths compares a left and right Swagger or OpenAPI Paths Object for changes. If found, returns a pointer
|
||||
// to a PathsChanges instance. Returns nil if nothing is found.
|
||||
func ComparePaths(l, r any) *PathsChanges {
|
||||
|
||||
var changes []*Change
|
||||
var changes []*Change
|
||||
|
||||
pc := new(PathsChanges)
|
||||
pathChanges := make(map[string]*PathItemChanges)
|
||||
pc := new(PathsChanges)
|
||||
pathChanges := make(map[string]*PathItemChanges)
|
||||
|
||||
// Swagger
|
||||
if reflect.TypeOf(&v2.Paths{}) == reflect.TypeOf(l) &&
|
||||
reflect.TypeOf(&v2.Paths{}) == reflect.TypeOf(r) {
|
||||
// Swagger
|
||||
if reflect.TypeOf(&v2.Paths{}) == reflect.TypeOf(l) &&
|
||||
reflect.TypeOf(&v2.Paths{}) == reflect.TypeOf(r) {
|
||||
|
||||
lPath := l.(*v2.Paths)
|
||||
rPath := r.(*v2.Paths)
|
||||
lPath := l.(*v2.Paths)
|
||||
rPath := r.(*v2.Paths)
|
||||
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lPath, rPath) {
|
||||
return nil
|
||||
}
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lPath, rPath) {
|
||||
return nil
|
||||
}
|
||||
|
||||
lKeys := make(map[string]low.ValueReference[*v2.PathItem])
|
||||
rKeys := make(map[string]low.ValueReference[*v2.PathItem])
|
||||
for k := range lPath.PathItems {
|
||||
lKeys[k.Value] = lPath.PathItems[k]
|
||||
}
|
||||
for k := range rPath.PathItems {
|
||||
rKeys[k.Value] = rPath.PathItems[k]
|
||||
}
|
||||
lKeys := make(map[string]low.ValueReference[*v2.PathItem])
|
||||
rKeys := make(map[string]low.ValueReference[*v2.PathItem])
|
||||
for k := range lPath.PathItems {
|
||||
lKeys[k.Value] = lPath.PathItems[k]
|
||||
}
|
||||
for k := range rPath.PathItems {
|
||||
rKeys[k.Value] = rPath.PathItems[k]
|
||||
}
|
||||
|
||||
// run every comparison in a thread.
|
||||
var mLock sync.Mutex
|
||||
compare := func(path string, pChanges map[string]*PathItemChanges, l, r *v2.PathItem, doneChan chan bool) {
|
||||
if !low.AreEqual(l, r) {
|
||||
mLock.Lock()
|
||||
pathChanges[path] = ComparePathItems(l, r)
|
||||
mLock.Unlock()
|
||||
}
|
||||
doneChan <- true
|
||||
}
|
||||
// run every comparison in a thread.
|
||||
var mLock sync.Mutex
|
||||
compare := func(path string, pChanges map[string]*PathItemChanges, l, r *v2.PathItem, doneChan chan bool) {
|
||||
if !low.AreEqual(l, r) {
|
||||
mLock.Lock()
|
||||
pathChanges[path] = ComparePathItems(l, r)
|
||||
mLock.Unlock()
|
||||
}
|
||||
doneChan <- true
|
||||
}
|
||||
|
||||
doneChan := make(chan bool)
|
||||
pathsChecked := 0
|
||||
doneChan := make(chan bool)
|
||||
pathsChecked := 0
|
||||
|
||||
for k := range lKeys {
|
||||
if _, ok := rKeys[k]; ok {
|
||||
go compare(k, pathChanges, lKeys[k].Value, rKeys[k].Value, doneChan)
|
||||
pathsChecked++
|
||||
continue
|
||||
}
|
||||
g, p := lPath.FindPathAndKey(k)
|
||||
CreateChange(&changes, ObjectRemoved, v3.PathLabel,
|
||||
g.KeyNode, nil, true,
|
||||
p.Value, nil)
|
||||
}
|
||||
for k := range lKeys {
|
||||
if _, ok := rKeys[k]; ok {
|
||||
go compare(k, pathChanges, lKeys[k].Value, rKeys[k].Value, doneChan)
|
||||
pathsChecked++
|
||||
continue
|
||||
}
|
||||
g, p := lPath.FindPathAndKey(k)
|
||||
CreateChange(&changes, ObjectRemoved, v3.PathLabel,
|
||||
g.KeyNode, nil, true,
|
||||
p.Value, nil)
|
||||
}
|
||||
|
||||
for k := range rKeys {
|
||||
if _, ok := lKeys[k]; !ok {
|
||||
g, p := rPath.FindPathAndKey(k)
|
||||
CreateChange(&changes, ObjectAdded, v3.PathLabel,
|
||||
nil, g.KeyNode, false,
|
||||
nil, p.Value)
|
||||
}
|
||||
}
|
||||
for k := range rKeys {
|
||||
if _, ok := lKeys[k]; !ok {
|
||||
g, p := rPath.FindPathAndKey(k)
|
||||
CreateChange(&changes, ObjectAdded, v3.PathLabel,
|
||||
nil, g.KeyNode, false,
|
||||
nil, p.Value)
|
||||
}
|
||||
}
|
||||
|
||||
// wait for the things to be done.
|
||||
completedChecks := 0
|
||||
for completedChecks < pathsChecked {
|
||||
select {
|
||||
case <-doneChan:
|
||||
completedChecks++
|
||||
}
|
||||
}
|
||||
if len(pathChanges) > 0 {
|
||||
pc.PathItemsChanges = pathChanges
|
||||
}
|
||||
// wait for the things to be done.
|
||||
completedChecks := 0
|
||||
for completedChecks < pathsChecked {
|
||||
select {
|
||||
case <-doneChan:
|
||||
completedChecks++
|
||||
}
|
||||
}
|
||||
if len(pathChanges) > 0 {
|
||||
pc.PathItemsChanges = pathChanges
|
||||
}
|
||||
|
||||
pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions)
|
||||
}
|
||||
pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions)
|
||||
}
|
||||
|
||||
// OpenAPI
|
||||
if reflect.TypeOf(&v3.Paths{}) == reflect.TypeOf(l) &&
|
||||
reflect.TypeOf(&v3.Paths{}) == reflect.TypeOf(r) {
|
||||
// OpenAPI
|
||||
if reflect.TypeOf(&v3.Paths{}) == reflect.TypeOf(l) &&
|
||||
reflect.TypeOf(&v3.Paths{}) == reflect.TypeOf(r) {
|
||||
|
||||
lPath := l.(*v3.Paths)
|
||||
rPath := r.(*v3.Paths)
|
||||
lPath := l.(*v3.Paths)
|
||||
rPath := r.(*v3.Paths)
|
||||
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lPath, rPath) {
|
||||
return nil
|
||||
}
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lPath, rPath) {
|
||||
return nil
|
||||
}
|
||||
|
||||
lKeys := make(map[string]low.ValueReference[*v3.PathItem])
|
||||
rKeys := make(map[string]low.ValueReference[*v3.PathItem])
|
||||
for k := range lPath.PathItems {
|
||||
lKeys[k.Value] = lPath.PathItems[k]
|
||||
}
|
||||
for k := range rPath.PathItems {
|
||||
rKeys[k.Value] = rPath.PathItems[k]
|
||||
}
|
||||
lKeys := make(map[string]low.ValueReference[*v3.PathItem])
|
||||
rKeys := make(map[string]low.ValueReference[*v3.PathItem])
|
||||
for k := range lPath.PathItems {
|
||||
lKeys[k.Value] = lPath.PathItems[k]
|
||||
}
|
||||
for k := range rPath.PathItems {
|
||||
rKeys[k.Value] = rPath.PathItems[k]
|
||||
}
|
||||
|
||||
// run every comparison in a thread.
|
||||
var mLock sync.Mutex
|
||||
compare := func(path string, pChanges map[string]*PathItemChanges, l, r *v3.PathItem, doneChan chan bool) {
|
||||
if !low.AreEqual(l, r) {
|
||||
mLock.Lock()
|
||||
pathChanges[path] = ComparePathItems(l, r)
|
||||
mLock.Unlock()
|
||||
}
|
||||
doneChan <- true
|
||||
}
|
||||
// run every comparison in a thread.
|
||||
var mLock sync.Mutex
|
||||
compare := func(path string, pChanges map[string]*PathItemChanges, l, r *v3.PathItem, doneChan chan bool) {
|
||||
if !low.AreEqual(l, r) {
|
||||
mLock.Lock()
|
||||
pathChanges[path] = ComparePathItems(l, r)
|
||||
mLock.Unlock()
|
||||
}
|
||||
doneChan <- true
|
||||
}
|
||||
|
||||
doneChan := make(chan bool)
|
||||
pathsChecked := 0
|
||||
doneChan := make(chan bool)
|
||||
pathsChecked := 0
|
||||
|
||||
for k := range lKeys {
|
||||
if _, ok := rKeys[k]; ok {
|
||||
go compare(k, pathChanges, lKeys[k].Value, rKeys[k].Value, doneChan)
|
||||
pathsChecked++
|
||||
continue
|
||||
}
|
||||
g, p := lPath.FindPathAndKey(k)
|
||||
CreateChange(&changes, ObjectRemoved, v3.PathLabel,
|
||||
g.KeyNode, nil, true,
|
||||
p.Value, nil)
|
||||
}
|
||||
for k := range lKeys {
|
||||
if _, ok := rKeys[k]; ok {
|
||||
go compare(k, pathChanges, lKeys[k].Value, rKeys[k].Value, doneChan)
|
||||
pathsChecked++
|
||||
continue
|
||||
}
|
||||
g, p := lPath.FindPathAndKey(k)
|
||||
CreateChange(&changes, ObjectRemoved, v3.PathLabel,
|
||||
g.KeyNode, nil, true,
|
||||
p.Value, nil)
|
||||
}
|
||||
|
||||
for k := range rKeys {
|
||||
if _, ok := lKeys[k]; !ok {
|
||||
g, p := rPath.FindPathAndKey(k)
|
||||
CreateChange(&changes, ObjectAdded, v3.PathLabel,
|
||||
nil, g.KeyNode, false,
|
||||
nil, p.Value)
|
||||
}
|
||||
}
|
||||
// wait for the things to be done.
|
||||
completedChecks := 0
|
||||
for completedChecks < pathsChecked {
|
||||
select {
|
||||
case <-doneChan:
|
||||
completedChecks++
|
||||
}
|
||||
}
|
||||
if len(pathChanges) > 0 {
|
||||
pc.PathItemsChanges = pathChanges
|
||||
}
|
||||
for k := range rKeys {
|
||||
if _, ok := lKeys[k]; !ok {
|
||||
g, p := rPath.FindPathAndKey(k)
|
||||
CreateChange(&changes, ObjectAdded, v3.PathLabel,
|
||||
nil, g.KeyNode, false,
|
||||
nil, p.Value)
|
||||
}
|
||||
}
|
||||
// wait for the things to be done.
|
||||
completedChecks := 0
|
||||
for completedChecks < pathsChecked {
|
||||
select {
|
||||
case <-doneChan:
|
||||
completedChecks++
|
||||
}
|
||||
}
|
||||
if len(pathChanges) > 0 {
|
||||
pc.PathItemsChanges = pathChanges
|
||||
}
|
||||
|
||||
pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions)
|
||||
}
|
||||
pc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return pc
|
||||
pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions)
|
||||
}
|
||||
pc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return pc
|
||||
}
|
||||
|
||||
@@ -4,90 +4,90 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// RequestBodyChanges represents changes made between two OpenAPI RequestBody Objects
|
||||
type RequestBodyChanges struct {
|
||||
*PropertyChanges
|
||||
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
*PropertyChanges
|
||||
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between RequestBody objects
|
||||
func (rb *RequestBodyChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, rb.Changes...)
|
||||
for k := range rb.ContentChanges {
|
||||
changes = append(changes, rb.ContentChanges[k].GetAllChanges()...)
|
||||
}
|
||||
if rb.ExtensionChanges != nil {
|
||||
changes = append(changes, rb.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, rb.Changes...)
|
||||
for k := range rb.ContentChanges {
|
||||
changes = append(changes, rb.ContentChanges[k].GetAllChanges()...)
|
||||
}
|
||||
if rb.ExtensionChanges != nil {
|
||||
changes = append(changes, rb.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the total number of changes found between two OpenAPI RequestBody objects
|
||||
func (rb *RequestBodyChanges) TotalChanges() int {
|
||||
c := rb.PropertyChanges.TotalChanges()
|
||||
for k := range rb.ContentChanges {
|
||||
c += rb.ContentChanges[k].TotalChanges()
|
||||
}
|
||||
if rb.ExtensionChanges != nil {
|
||||
c += rb.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := rb.PropertyChanges.TotalChanges()
|
||||
for k := range rb.ContentChanges {
|
||||
c += rb.ContentChanges[k].TotalChanges()
|
||||
}
|
||||
if rb.ExtensionChanges != nil {
|
||||
c += rb.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the total number of breaking changes found between OpenAPI RequestBody objects
|
||||
func (rb *RequestBodyChanges) TotalBreakingChanges() int {
|
||||
c := rb.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range rb.ContentChanges {
|
||||
c += rb.ContentChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
c := rb.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range rb.ContentChanges {
|
||||
c += rb.ContentChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CompareRequestBodies compares a left and right OpenAPI RequestBody object for changes. If found returns a pointer
|
||||
// to a RequestBodyChanges instance. Returns nil if nothing was found.
|
||||
func CompareRequestBodies(l, r *v3.RequestBody) *RequestBodyChanges {
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
|
||||
// description
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Description.ValueNode,
|
||||
RightNode: r.Description.ValueNode,
|
||||
Label: v3.DescriptionLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// description
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Description.ValueNode,
|
||||
RightNode: r.Description.ValueNode,
|
||||
Label: v3.DescriptionLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// required
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Required.ValueNode,
|
||||
RightNode: r.Required.ValueNode,
|
||||
Label: v3.RequiredLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// required
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Required.ValueNode,
|
||||
RightNode: r.Required.ValueNode,
|
||||
Label: v3.RequiredLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
CheckProperties(props)
|
||||
CheckProperties(props)
|
||||
|
||||
rbc := new(RequestBodyChanges)
|
||||
rbc.ContentChanges = CheckMapForChanges(l.Content.Value, r.Content.Value,
|
||||
&changes, v3.ContentLabel, CompareMediaTypes)
|
||||
rbc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
rbc.PropertyChanges = NewPropertyChanges(changes)
|
||||
rbc := new(RequestBodyChanges)
|
||||
rbc.ContentChanges = CheckMapForChanges(l.Content.Value, r.Content.Value,
|
||||
&changes, v3.ContentLabel, CompareMediaTypes)
|
||||
rbc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
rbc.PropertyChanges = NewPropertyChanges(changes)
|
||||
|
||||
return rbc
|
||||
return rbc
|
||||
}
|
||||
|
||||
@@ -4,49 +4,49 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompareRequestBodies(t *testing.T) {
|
||||
|
||||
left := `description: something
|
||||
left := `description: something
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: int`
|
||||
|
||||
right := `description: something
|
||||
right := `description: something
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: int`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.RequestBody
|
||||
var rDoc v3.RequestBody
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.RequestBody
|
||||
var rDoc v3.RequestBody
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareRequestBodies(&lDoc, &rDoc)
|
||||
assert.Nil(t, extChanges)
|
||||
// compare.
|
||||
extChanges := CompareRequestBodies(&lDoc, &rDoc)
|
||||
assert.Nil(t, extChanges)
|
||||
}
|
||||
|
||||
func TestCompareRequestBodies_Modified(t *testing.T) {
|
||||
|
||||
left := `description: something
|
||||
left := `description: something
|
||||
required: true
|
||||
x-pizza: thin
|
||||
content:
|
||||
@@ -54,7 +54,7 @@ content:
|
||||
schema:
|
||||
type: int`
|
||||
|
||||
right := `x-pizza: oven
|
||||
right := `x-pizza: oven
|
||||
description: nothing
|
||||
required: false
|
||||
content:
|
||||
@@ -62,22 +62,22 @@ content:
|
||||
schema:
|
||||
type: string`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.RequestBody
|
||||
var rDoc v3.RequestBody
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.RequestBody
|
||||
var rDoc v3.RequestBody
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareRequestBodies(&lDoc, &rDoc)
|
||||
// compare.
|
||||
extChanges := CompareRequestBodies(&lDoc, &rDoc)
|
||||
|
||||
assert.Equal(t, 4, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 4)
|
||||
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, 4, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 4)
|
||||
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
|
||||
}
|
||||
|
||||
@@ -4,196 +4,196 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"reflect"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
)
|
||||
|
||||
// ResponseChanges represents changes found between two Swagger or OpenAPI Response objects.
|
||||
type ResponseChanges struct {
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
HeadersChanges map[string]*HeaderChanges `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
HeadersChanges map[string]*HeaderChanges `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
|
||||
// Swagger Response Properties.
|
||||
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||
ExamplesChanges *ExamplesChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
// Swagger Response Properties.
|
||||
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||
ExamplesChanges *ExamplesChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
|
||||
// OpenAPI Response Properties.
|
||||
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
LinkChanges map[string]*LinkChanges `json:"links,omitempty" yaml:"links,omitempty"`
|
||||
// OpenAPI Response Properties.
|
||||
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
LinkChanges map[string]*LinkChanges `json:"links,omitempty" yaml:"links,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between RequestBody objects
|
||||
func (r *ResponseChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, r.Changes...)
|
||||
if r.ExtensionChanges != nil {
|
||||
changes = append(changes, r.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
if r.SchemaChanges != nil {
|
||||
changes = append(changes, r.SchemaChanges.GetAllChanges()...)
|
||||
}
|
||||
if r.ExamplesChanges != nil {
|
||||
changes = append(changes, r.ExamplesChanges.GetAllChanges()...)
|
||||
}
|
||||
for k := range r.HeadersChanges {
|
||||
changes = append(changes, r.HeadersChanges[k].GetAllChanges()...)
|
||||
}
|
||||
for k := range r.ContentChanges {
|
||||
changes = append(changes, r.ContentChanges[k].GetAllChanges()...)
|
||||
}
|
||||
for k := range r.LinkChanges {
|
||||
changes = append(changes, r.LinkChanges[k].GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, r.Changes...)
|
||||
if r.ExtensionChanges != nil {
|
||||
changes = append(changes, r.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
if r.SchemaChanges != nil {
|
||||
changes = append(changes, r.SchemaChanges.GetAllChanges()...)
|
||||
}
|
||||
if r.ExamplesChanges != nil {
|
||||
changes = append(changes, r.ExamplesChanges.GetAllChanges()...)
|
||||
}
|
||||
for k := range r.HeadersChanges {
|
||||
changes = append(changes, r.HeadersChanges[k].GetAllChanges()...)
|
||||
}
|
||||
for k := range r.ContentChanges {
|
||||
changes = append(changes, r.ContentChanges[k].GetAllChanges()...)
|
||||
}
|
||||
for k := range r.LinkChanges {
|
||||
changes = append(changes, r.LinkChanges[k].GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the total number of changes found between two Swagger or OpenAPI Response Objects
|
||||
func (r *ResponseChanges) TotalChanges() int {
|
||||
c := r.PropertyChanges.TotalChanges()
|
||||
if r.ExtensionChanges != nil {
|
||||
c += r.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
if r.SchemaChanges != nil {
|
||||
c += r.SchemaChanges.TotalChanges()
|
||||
}
|
||||
if r.ExamplesChanges != nil {
|
||||
c += r.ExamplesChanges.TotalChanges()
|
||||
}
|
||||
for k := range r.HeadersChanges {
|
||||
c += r.HeadersChanges[k].TotalChanges()
|
||||
}
|
||||
for k := range r.ContentChanges {
|
||||
c += r.ContentChanges[k].TotalChanges()
|
||||
}
|
||||
for k := range r.LinkChanges {
|
||||
c += r.LinkChanges[k].TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := r.PropertyChanges.TotalChanges()
|
||||
if r.ExtensionChanges != nil {
|
||||
c += r.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
if r.SchemaChanges != nil {
|
||||
c += r.SchemaChanges.TotalChanges()
|
||||
}
|
||||
if r.ExamplesChanges != nil {
|
||||
c += r.ExamplesChanges.TotalChanges()
|
||||
}
|
||||
for k := range r.HeadersChanges {
|
||||
c += r.HeadersChanges[k].TotalChanges()
|
||||
}
|
||||
for k := range r.ContentChanges {
|
||||
c += r.ContentChanges[k].TotalChanges()
|
||||
}
|
||||
for k := range r.LinkChanges {
|
||||
c += r.LinkChanges[k].TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the total number of breaking changes found between two swagger or OpenAPI
|
||||
// Response Objects
|
||||
func (r *ResponseChanges) TotalBreakingChanges() int {
|
||||
c := r.PropertyChanges.TotalBreakingChanges()
|
||||
if r.SchemaChanges != nil {
|
||||
c += r.SchemaChanges.TotalBreakingChanges()
|
||||
}
|
||||
for k := range r.HeadersChanges {
|
||||
c += r.HeadersChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
for k := range r.ContentChanges {
|
||||
c += r.ContentChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
for k := range r.LinkChanges {
|
||||
c += r.LinkChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
c := r.PropertyChanges.TotalBreakingChanges()
|
||||
if r.SchemaChanges != nil {
|
||||
c += r.SchemaChanges.TotalBreakingChanges()
|
||||
}
|
||||
for k := range r.HeadersChanges {
|
||||
c += r.HeadersChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
for k := range r.ContentChanges {
|
||||
c += r.ContentChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
for k := range r.LinkChanges {
|
||||
c += r.LinkChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CompareResponseV2 is a Swagger type safe proxy for CompareResponse
|
||||
func CompareResponseV2(l, r *v2.Response) *ResponseChanges {
|
||||
return CompareResponse(l, r)
|
||||
return CompareResponse(l, r)
|
||||
}
|
||||
|
||||
// CompareResponseV3 is an OpenAPI type safe proxy for CompareResponse
|
||||
func CompareResponseV3(l, r *v3.Response) *ResponseChanges {
|
||||
return CompareResponse(l, r)
|
||||
return CompareResponse(l, r)
|
||||
}
|
||||
|
||||
// CompareResponse compares a left and right Swagger or OpenAPI Response object. If anything is found
|
||||
// a pointer to a ResponseChanges is returned, otherwise it returns nil.
|
||||
func CompareResponse(l, r any) *ResponseChanges {
|
||||
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
|
||||
rc := new(ResponseChanges)
|
||||
rc := new(ResponseChanges)
|
||||
|
||||
if reflect.TypeOf(&v2.Response{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Response{}) == reflect.TypeOf(r) {
|
||||
if reflect.TypeOf(&v2.Response{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Response{}) == reflect.TypeOf(r) {
|
||||
|
||||
lResponse := l.(*v2.Response)
|
||||
rResponse := r.(*v2.Response)
|
||||
lResponse := l.(*v2.Response)
|
||||
rResponse := r.(*v2.Response)
|
||||
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lResponse, rResponse) {
|
||||
return nil
|
||||
}
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lResponse, rResponse) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// description
|
||||
addPropertyCheck(&props, lResponse.Description.ValueNode, rResponse.Description.ValueNode,
|
||||
lResponse.Description.Value, rResponse.Description.Value, &changes, v3.DescriptionLabel, false)
|
||||
// description
|
||||
addPropertyCheck(&props, lResponse.Description.ValueNode, rResponse.Description.ValueNode,
|
||||
lResponse.Description.Value, rResponse.Description.Value, &changes, v3.DescriptionLabel, false)
|
||||
|
||||
if !lResponse.Schema.IsEmpty() && !rResponse.Schema.IsEmpty() {
|
||||
rc.SchemaChanges = CompareSchemas(lResponse.Schema.Value, rResponse.Schema.Value)
|
||||
}
|
||||
if !lResponse.Schema.IsEmpty() && rResponse.Schema.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel,
|
||||
lResponse.Schema.ValueNode, nil, true,
|
||||
lResponse.Schema.Value, nil)
|
||||
}
|
||||
if lResponse.Schema.IsEmpty() && !rResponse.Schema.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.SchemaLabel,
|
||||
nil, rResponse.Schema.ValueNode, true,
|
||||
nil, rResponse.Schema.Value)
|
||||
}
|
||||
if !lResponse.Schema.IsEmpty() && !rResponse.Schema.IsEmpty() {
|
||||
rc.SchemaChanges = CompareSchemas(lResponse.Schema.Value, rResponse.Schema.Value)
|
||||
}
|
||||
if !lResponse.Schema.IsEmpty() && rResponse.Schema.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel,
|
||||
lResponse.Schema.ValueNode, nil, true,
|
||||
lResponse.Schema.Value, nil)
|
||||
}
|
||||
if lResponse.Schema.IsEmpty() && !rResponse.Schema.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.SchemaLabel,
|
||||
nil, rResponse.Schema.ValueNode, true,
|
||||
nil, rResponse.Schema.Value)
|
||||
}
|
||||
|
||||
rc.HeadersChanges =
|
||||
CheckMapForChanges(lResponse.Headers.Value, rResponse.Headers.Value,
|
||||
&changes, v3.HeadersLabel, CompareHeadersV2)
|
||||
rc.HeadersChanges =
|
||||
CheckMapForChanges(lResponse.Headers.Value, rResponse.Headers.Value,
|
||||
&changes, v3.HeadersLabel, CompareHeadersV2)
|
||||
|
||||
if !lResponse.Examples.IsEmpty() && !rResponse.Examples.IsEmpty() {
|
||||
rc.ExamplesChanges = CompareExamplesV2(lResponse.Examples.Value, rResponse.Examples.Value)
|
||||
}
|
||||
if !lResponse.Examples.IsEmpty() && rResponse.Examples.IsEmpty() {
|
||||
CreateChange(&changes, PropertyRemoved, v3.ExamplesLabel,
|
||||
lResponse.Schema.ValueNode, nil, false,
|
||||
lResponse.Schema.Value, nil)
|
||||
}
|
||||
if lResponse.Examples.IsEmpty() && !rResponse.Examples.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.ExamplesLabel,
|
||||
nil, rResponse.Schema.ValueNode, false,
|
||||
nil, lResponse.Schema.Value)
|
||||
}
|
||||
if !lResponse.Examples.IsEmpty() && !rResponse.Examples.IsEmpty() {
|
||||
rc.ExamplesChanges = CompareExamplesV2(lResponse.Examples.Value, rResponse.Examples.Value)
|
||||
}
|
||||
if !lResponse.Examples.IsEmpty() && rResponse.Examples.IsEmpty() {
|
||||
CreateChange(&changes, PropertyRemoved, v3.ExamplesLabel,
|
||||
lResponse.Schema.ValueNode, nil, false,
|
||||
lResponse.Schema.Value, nil)
|
||||
}
|
||||
if lResponse.Examples.IsEmpty() && !rResponse.Examples.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.ExamplesLabel,
|
||||
nil, rResponse.Schema.ValueNode, false,
|
||||
nil, lResponse.Schema.Value)
|
||||
}
|
||||
|
||||
rc.ExtensionChanges = CompareExtensions(lResponse.Extensions, rResponse.Extensions)
|
||||
}
|
||||
rc.ExtensionChanges = CompareExtensions(lResponse.Extensions, rResponse.Extensions)
|
||||
}
|
||||
|
||||
if reflect.TypeOf(&v3.Response{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Response{}) == reflect.TypeOf(r) {
|
||||
if reflect.TypeOf(&v3.Response{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Response{}) == reflect.TypeOf(r) {
|
||||
|
||||
lResponse := l.(*v3.Response)
|
||||
rResponse := r.(*v3.Response)
|
||||
lResponse := l.(*v3.Response)
|
||||
rResponse := r.(*v3.Response)
|
||||
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lResponse, rResponse) {
|
||||
return nil
|
||||
}
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lResponse, rResponse) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// description
|
||||
addPropertyCheck(&props, lResponse.Description.ValueNode, rResponse.Description.ValueNode,
|
||||
lResponse.Description.Value, lResponse.Description.Value, &changes, v3.DescriptionLabel, false)
|
||||
// description
|
||||
addPropertyCheck(&props, lResponse.Description.ValueNode, rResponse.Description.ValueNode,
|
||||
lResponse.Description.Value, lResponse.Description.Value, &changes, v3.DescriptionLabel, false)
|
||||
|
||||
rc.HeadersChanges =
|
||||
CheckMapForChanges(lResponse.Headers.Value, rResponse.Headers.Value,
|
||||
&changes, v3.HeadersLabel, CompareHeadersV3)
|
||||
rc.HeadersChanges =
|
||||
CheckMapForChanges(lResponse.Headers.Value, rResponse.Headers.Value,
|
||||
&changes, v3.HeadersLabel, CompareHeadersV3)
|
||||
|
||||
rc.ContentChanges =
|
||||
CheckMapForChanges(lResponse.Content.Value, rResponse.Content.Value,
|
||||
&changes, v3.ContentLabel, CompareMediaTypes)
|
||||
rc.ContentChanges =
|
||||
CheckMapForChanges(lResponse.Content.Value, rResponse.Content.Value,
|
||||
&changes, v3.ContentLabel, CompareMediaTypes)
|
||||
|
||||
rc.LinkChanges =
|
||||
CheckMapForChanges(lResponse.Links.Value, rResponse.Links.Value,
|
||||
&changes, v3.LinksLabel, CompareLinks)
|
||||
rc.LinkChanges =
|
||||
CheckMapForChanges(lResponse.Links.Value, rResponse.Links.Value,
|
||||
&changes, v3.LinksLabel, CompareLinks)
|
||||
|
||||
rc.ExtensionChanges = CompareExtensions(lResponse.Extensions, rResponse.Extensions)
|
||||
}
|
||||
rc.ExtensionChanges = CompareExtensions(lResponse.Extensions, rResponse.Extensions)
|
||||
}
|
||||
|
||||
CheckProperties(props)
|
||||
rc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return rc
|
||||
CheckProperties(props)
|
||||
rc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return rc
|
||||
}
|
||||
|
||||
@@ -4,137 +4,137 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"reflect"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// ResponsesChanges represents changes made between two Swagger or OpenAPI Responses objects.
|
||||
type ResponsesChanges struct {
|
||||
*PropertyChanges
|
||||
ResponseChanges map[string]*ResponseChanges `json:"response,omitempty" yaml:"response,omitempty"`
|
||||
DefaultChanges *ResponseChanges `json:"default,omitempty" yaml:"default,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
*PropertyChanges
|
||||
ResponseChanges map[string]*ResponseChanges `json:"response,omitempty" yaml:"response,omitempty"`
|
||||
DefaultChanges *ResponseChanges `json:"default,omitempty" yaml:"default,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Responses objects
|
||||
func (r *ResponsesChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, r.Changes...)
|
||||
for k := range r.ResponseChanges {
|
||||
changes = append(changes, r.ResponseChanges[k].GetAllChanges()...)
|
||||
}
|
||||
if r.DefaultChanges != nil {
|
||||
changes = append(changes, r.DefaultChanges.GetAllChanges()...)
|
||||
}
|
||||
if r.ExtensionChanges != nil {
|
||||
changes = append(changes, r.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, r.Changes...)
|
||||
for k := range r.ResponseChanges {
|
||||
changes = append(changes, r.ResponseChanges[k].GetAllChanges()...)
|
||||
}
|
||||
if r.DefaultChanges != nil {
|
||||
changes = append(changes, r.DefaultChanges.GetAllChanges()...)
|
||||
}
|
||||
if r.ExtensionChanges != nil {
|
||||
changes = append(changes, r.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the total number of changes found between two Swagger or OpenAPI Responses objects
|
||||
func (r *ResponsesChanges) TotalChanges() int {
|
||||
c := r.PropertyChanges.TotalChanges()
|
||||
for k := range r.ResponseChanges {
|
||||
c += r.ResponseChanges[k].TotalChanges()
|
||||
}
|
||||
if r.DefaultChanges != nil {
|
||||
c += r.DefaultChanges.TotalChanges()
|
||||
}
|
||||
if r.ExtensionChanges != nil {
|
||||
c += r.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := r.PropertyChanges.TotalChanges()
|
||||
for k := range r.ResponseChanges {
|
||||
c += r.ResponseChanges[k].TotalChanges()
|
||||
}
|
||||
if r.DefaultChanges != nil {
|
||||
c += r.DefaultChanges.TotalChanges()
|
||||
}
|
||||
if r.ExtensionChanges != nil {
|
||||
c += r.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the total number of changes found between two Swagger or OpenAPI
|
||||
// Responses Objects
|
||||
func (r *ResponsesChanges) TotalBreakingChanges() int {
|
||||
c := r.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range r.ResponseChanges {
|
||||
c += r.ResponseChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
if r.DefaultChanges != nil {
|
||||
c += r.DefaultChanges.TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
c := r.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range r.ResponseChanges {
|
||||
c += r.ResponseChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
if r.DefaultChanges != nil {
|
||||
c += r.DefaultChanges.TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CompareResponses compares a left and right Swagger or OpenAPI Responses object for any changes. If found
|
||||
// returns a pointer to ResponsesChanges, or returns nil.
|
||||
func CompareResponses(l, r any) *ResponsesChanges {
|
||||
|
||||
var changes []*Change
|
||||
var changes []*Change
|
||||
|
||||
rc := new(ResponsesChanges)
|
||||
rc := new(ResponsesChanges)
|
||||
|
||||
// swagger
|
||||
if reflect.TypeOf(&v2.Responses{}) == reflect.TypeOf(l) &&
|
||||
reflect.TypeOf(&v2.Responses{}) == reflect.TypeOf(r) {
|
||||
// swagger
|
||||
if reflect.TypeOf(&v2.Responses{}) == reflect.TypeOf(l) &&
|
||||
reflect.TypeOf(&v2.Responses{}) == reflect.TypeOf(r) {
|
||||
|
||||
lResponses := l.(*v2.Responses)
|
||||
rResponses := r.(*v2.Responses)
|
||||
lResponses := l.(*v2.Responses)
|
||||
rResponses := r.(*v2.Responses)
|
||||
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lResponses, rResponses) {
|
||||
return nil
|
||||
}
|
||||
// perform hash check to avoid further processing
|
||||
if low.AreEqual(lResponses, rResponses) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
||||
rc.DefaultChanges = CompareResponse(lResponses.Default.Value, rResponses.Default.Value)
|
||||
}
|
||||
if !lResponses.Default.IsEmpty() && rResponses.Default.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.DefaultLabel,
|
||||
lResponses.Default.ValueNode, nil, true,
|
||||
lResponses.Default.Value, nil)
|
||||
}
|
||||
if lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.DefaultLabel,
|
||||
nil, rResponses.Default.ValueNode, false,
|
||||
nil, lResponses.Default.Value)
|
||||
}
|
||||
if !lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
||||
rc.DefaultChanges = CompareResponse(lResponses.Default.Value, rResponses.Default.Value)
|
||||
}
|
||||
if !lResponses.Default.IsEmpty() && rResponses.Default.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.DefaultLabel,
|
||||
lResponses.Default.ValueNode, nil, true,
|
||||
lResponses.Default.Value, nil)
|
||||
}
|
||||
if lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.DefaultLabel,
|
||||
nil, rResponses.Default.ValueNode, false,
|
||||
nil, lResponses.Default.Value)
|
||||
}
|
||||
|
||||
rc.ResponseChanges = CheckMapForChanges(lResponses.Codes, rResponses.Codes,
|
||||
&changes, v3.CodesLabel, CompareResponseV2)
|
||||
rc.ResponseChanges = CheckMapForChanges(lResponses.Codes, rResponses.Codes,
|
||||
&changes, v3.CodesLabel, CompareResponseV2)
|
||||
|
||||
rc.ExtensionChanges = CompareExtensions(lResponses.Extensions, rResponses.Extensions)
|
||||
}
|
||||
rc.ExtensionChanges = CompareExtensions(lResponses.Extensions, rResponses.Extensions)
|
||||
}
|
||||
|
||||
// openapi
|
||||
if reflect.TypeOf(&v3.Responses{}) == reflect.TypeOf(l) &&
|
||||
reflect.TypeOf(&v3.Responses{}) == reflect.TypeOf(r) {
|
||||
// openapi
|
||||
if reflect.TypeOf(&v3.Responses{}) == reflect.TypeOf(l) &&
|
||||
reflect.TypeOf(&v3.Responses{}) == reflect.TypeOf(r) {
|
||||
|
||||
lResponses := l.(*v3.Responses)
|
||||
rResponses := r.(*v3.Responses)
|
||||
lResponses := l.(*v3.Responses)
|
||||
rResponses := r.(*v3.Responses)
|
||||
|
||||
//perform hash check to avoid further processing
|
||||
if low.AreEqual(lResponses, rResponses) {
|
||||
return nil
|
||||
}
|
||||
//perform hash check to avoid further processing
|
||||
if low.AreEqual(lResponses, rResponses) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
||||
rc.DefaultChanges = CompareResponse(lResponses.Default.Value, rResponses.Default.Value)
|
||||
}
|
||||
if !lResponses.Default.IsEmpty() && rResponses.Default.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.DefaultLabel,
|
||||
lResponses.Default.ValueNode, nil, true,
|
||||
lResponses.Default.Value, nil)
|
||||
}
|
||||
if lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.DefaultLabel,
|
||||
nil, rResponses.Default.ValueNode, false,
|
||||
nil, lResponses.Default.Value)
|
||||
}
|
||||
if !lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
||||
rc.DefaultChanges = CompareResponse(lResponses.Default.Value, rResponses.Default.Value)
|
||||
}
|
||||
if !lResponses.Default.IsEmpty() && rResponses.Default.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.DefaultLabel,
|
||||
lResponses.Default.ValueNode, nil, true,
|
||||
lResponses.Default.Value, nil)
|
||||
}
|
||||
if lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.DefaultLabel,
|
||||
nil, rResponses.Default.ValueNode, false,
|
||||
nil, lResponses.Default.Value)
|
||||
}
|
||||
|
||||
rc.ResponseChanges = CheckMapForChanges(lResponses.Codes, rResponses.Codes,
|
||||
&changes, v3.CodesLabel, CompareResponseV3)
|
||||
rc.ResponseChanges = CheckMapForChanges(lResponses.Codes, rResponses.Codes,
|
||||
&changes, v3.CodesLabel, CompareResponseV3)
|
||||
|
||||
rc.ExtensionChanges = CompareExtensions(lResponses.Extensions, rResponses.Extensions)
|
||||
rc.ExtensionChanges = CompareExtensions(lResponses.Extensions, rResponses.Extensions)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
rc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return rc
|
||||
rc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return rc
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,73 +4,73 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// ScopesChanges represents changes between two Swagger Scopes Objects
|
||||
type ScopesChanges struct {
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Scopes objects
|
||||
func (s *ScopesChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, s.Changes...)
|
||||
if s.ExtensionChanges != nil {
|
||||
changes = append(changes, s.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, s.Changes...)
|
||||
if s.ExtensionChanges != nil {
|
||||
changes = append(changes, s.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the total changes found between two Swagger Scopes objects.
|
||||
func (s *ScopesChanges) TotalChanges() int {
|
||||
c := s.PropertyChanges.TotalChanges()
|
||||
if s.ExtensionChanges != nil {
|
||||
c += s.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := s.PropertyChanges.TotalChanges()
|
||||
if s.ExtensionChanges != nil {
|
||||
c += s.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the total number of breaking changes between two Swagger Scopes objects.
|
||||
func (s *ScopesChanges) TotalBreakingChanges() int {
|
||||
return s.PropertyChanges.TotalBreakingChanges()
|
||||
return s.PropertyChanges.TotalBreakingChanges()
|
||||
}
|
||||
|
||||
// CompareScopes compares a left and right Swagger Scopes objects for changes. If anything is found, returns
|
||||
// a pointer to ScopesChanges, or returns nil if nothing is found.
|
||||
func CompareScopes(l, r *v2.Scopes) *ScopesChanges {
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
var changes []*Change
|
||||
for v := range l.Values {
|
||||
if r != nil && r.FindScope(v.Value) == nil {
|
||||
CreateChange(&changes, ObjectRemoved, v3.Scopes,
|
||||
l.Values[v].ValueNode, nil, true,
|
||||
v.Value, nil)
|
||||
continue
|
||||
}
|
||||
if r != nil && r.FindScope(v.Value) != nil {
|
||||
if l.Values[v].Value != r.FindScope(v.Value).Value {
|
||||
CreateChange(&changes, Modified, v3.Scopes,
|
||||
l.Values[v].ValueNode, r.FindScope(v.Value).ValueNode, true,
|
||||
l.Values[v].Value, r.FindScope(v.Value).Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
for v := range r.Values {
|
||||
if l != nil && l.FindScope(v.Value) == nil {
|
||||
CreateChange(&changes, ObjectAdded, v3.Scopes,
|
||||
nil, r.Values[v].ValueNode, false,
|
||||
nil, v.Value)
|
||||
}
|
||||
}
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
var changes []*Change
|
||||
for v := range l.Values {
|
||||
if r != nil && r.FindScope(v.Value) == nil {
|
||||
CreateChange(&changes, ObjectRemoved, v3.Scopes,
|
||||
l.Values[v].ValueNode, nil, true,
|
||||
v.Value, nil)
|
||||
continue
|
||||
}
|
||||
if r != nil && r.FindScope(v.Value) != nil {
|
||||
if l.Values[v].Value != r.FindScope(v.Value).Value {
|
||||
CreateChange(&changes, Modified, v3.Scopes,
|
||||
l.Values[v].ValueNode, r.FindScope(v.Value).ValueNode, true,
|
||||
l.Values[v].Value, r.FindScope(v.Value).Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
for v := range r.Values {
|
||||
if l != nil && l.FindScope(v.Value) == nil {
|
||||
CreateChange(&changes, ObjectAdded, v3.Scopes,
|
||||
nil, r.Values[v].ValueNode, false,
|
||||
nil, v.Value)
|
||||
}
|
||||
}
|
||||
|
||||
sc := new(ScopesChanges)
|
||||
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||
sc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
return sc
|
||||
sc := new(ScopesChanges)
|
||||
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||
sc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||
return sc
|
||||
}
|
||||
|
||||
@@ -4,147 +4,147 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"gopkg.in/yaml.v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// SecurityRequirementChanges represents changes found between two SecurityRequirement Objects.
|
||||
type SecurityRequirementChanges struct {
|
||||
*PropertyChanges
|
||||
*PropertyChanges
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between SecurityRequirement objects
|
||||
func (s *SecurityRequirementChanges) GetAllChanges() []*Change {
|
||||
return s.Changes
|
||||
return s.Changes
|
||||
}
|
||||
|
||||
// TotalChanges returns the total number of changes between two SecurityRequirement Objects.
|
||||
func (s *SecurityRequirementChanges) TotalChanges() int {
|
||||
return s.PropertyChanges.TotalChanges()
|
||||
return s.PropertyChanges.TotalChanges()
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the total number of breaking changes between two SecurityRequirement Objects.
|
||||
func (s *SecurityRequirementChanges) TotalBreakingChanges() int {
|
||||
return s.PropertyChanges.TotalBreakingChanges()
|
||||
return s.PropertyChanges.TotalBreakingChanges()
|
||||
}
|
||||
|
||||
// CompareSecurityRequirement compares left and right SecurityRequirement objects for changes. If anything
|
||||
// is found, then a pointer to SecurityRequirementChanges is returned, otherwise nil.
|
||||
func CompareSecurityRequirement(l, r *base.SecurityRequirement) *SecurityRequirementChanges {
|
||||
|
||||
var changes []*Change
|
||||
sc := new(SecurityRequirementChanges)
|
||||
var changes []*Change
|
||||
sc := new(SecurityRequirementChanges)
|
||||
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
checkSecurityRequirement(l.Requirements.Value, r.Requirements.Value, &changes)
|
||||
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return sc
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
checkSecurityRequirement(l.Requirements.Value, r.Requirements.Value, &changes)
|
||||
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return sc
|
||||
}
|
||||
|
||||
func removedSecurityRequirement(vn *yaml.Node, name string, changes *[]*Change) {
|
||||
CreateChange(changes, ObjectRemoved, v3.SecurityLabel,
|
||||
vn, nil, true, name, nil)
|
||||
CreateChange(changes, ObjectRemoved, v3.SecurityLabel,
|
||||
vn, nil, true, name, nil)
|
||||
}
|
||||
|
||||
func addedSecurityRequirement(vn *yaml.Node, name string, changes *[]*Change) {
|
||||
CreateChange(changes, ObjectAdded, v3.SecurityLabel,
|
||||
nil, vn, false, nil, name)
|
||||
CreateChange(changes, ObjectAdded, v3.SecurityLabel,
|
||||
nil, vn, false, nil, name)
|
||||
}
|
||||
|
||||
// tricky to do this correctly, this is my solution.
|
||||
func checkSecurityRequirement(lSec, rSec map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]],
|
||||
changes *[]*Change) {
|
||||
changes *[]*Change) {
|
||||
|
||||
lKeys := make([]string, len(lSec))
|
||||
rKeys := make([]string, len(rSec))
|
||||
lValues := make(map[string]low.ValueReference[[]low.ValueReference[string]])
|
||||
rValues := make(map[string]low.ValueReference[[]low.ValueReference[string]])
|
||||
var n, z int
|
||||
for i := range lSec {
|
||||
lKeys[n] = i.Value
|
||||
lValues[i.Value] = lSec[i]
|
||||
n++
|
||||
}
|
||||
for i := range rSec {
|
||||
rKeys[z] = i.Value
|
||||
rValues[i.Value] = rSec[i]
|
||||
z++
|
||||
}
|
||||
lKeys := make([]string, len(lSec))
|
||||
rKeys := make([]string, len(rSec))
|
||||
lValues := make(map[string]low.ValueReference[[]low.ValueReference[string]])
|
||||
rValues := make(map[string]low.ValueReference[[]low.ValueReference[string]])
|
||||
var n, z int
|
||||
for i := range lSec {
|
||||
lKeys[n] = i.Value
|
||||
lValues[i.Value] = lSec[i]
|
||||
n++
|
||||
}
|
||||
for i := range rSec {
|
||||
rKeys[z] = i.Value
|
||||
rValues[i.Value] = rSec[i]
|
||||
z++
|
||||
}
|
||||
|
||||
for z = range lKeys {
|
||||
if z < len(rKeys) {
|
||||
if _, ok := rValues[lKeys[z]]; !ok {
|
||||
removedSecurityRequirement(lValues[lKeys[z]].ValueNode, lKeys[z], changes)
|
||||
continue
|
||||
}
|
||||
for z = range lKeys {
|
||||
if z < len(rKeys) {
|
||||
if _, ok := rValues[lKeys[z]]; !ok {
|
||||
removedSecurityRequirement(lValues[lKeys[z]].ValueNode, lKeys[z], changes)
|
||||
continue
|
||||
}
|
||||
|
||||
lValue := lValues[lKeys[z]].Value
|
||||
rValue := rValues[lKeys[z]].Value
|
||||
lValue := lValues[lKeys[z]].Value
|
||||
rValue := rValues[lKeys[z]].Value
|
||||
|
||||
// check if actual values match up
|
||||
lRoleKeys := make([]string, len(lValue))
|
||||
rRoleKeys := make([]string, len(rValue))
|
||||
lRoleValues := make(map[string]low.ValueReference[string])
|
||||
rRoleValues := make(map[string]low.ValueReference[string])
|
||||
var t, k int
|
||||
for i := range lValue {
|
||||
lRoleKeys[t] = lValue[i].Value
|
||||
lRoleValues[lValue[i].Value] = lValue[i]
|
||||
t++
|
||||
}
|
||||
for i := range rValue {
|
||||
rRoleKeys[k] = rValue[i].Value
|
||||
rRoleValues[rValue[i].Value] = rValue[i]
|
||||
k++
|
||||
}
|
||||
// check if actual values match up
|
||||
lRoleKeys := make([]string, len(lValue))
|
||||
rRoleKeys := make([]string, len(rValue))
|
||||
lRoleValues := make(map[string]low.ValueReference[string])
|
||||
rRoleValues := make(map[string]low.ValueReference[string])
|
||||
var t, k int
|
||||
for i := range lValue {
|
||||
lRoleKeys[t] = lValue[i].Value
|
||||
lRoleValues[lValue[i].Value] = lValue[i]
|
||||
t++
|
||||
}
|
||||
for i := range rValue {
|
||||
rRoleKeys[k] = rValue[i].Value
|
||||
rRoleValues[rValue[i].Value] = rValue[i]
|
||||
k++
|
||||
}
|
||||
|
||||
for t = range lRoleKeys {
|
||||
if t < len(rRoleKeys) {
|
||||
if _, ok := rRoleValues[lRoleKeys[t]]; !ok {
|
||||
removedSecurityRequirement(lRoleValues[lRoleKeys[t]].ValueNode, lRoleKeys[t], changes)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if t >= len(rRoleKeys) {
|
||||
if _, ok := rRoleValues[lRoleKeys[t]]; !ok {
|
||||
removedSecurityRequirement(lRoleValues[lRoleKeys[t]].ValueNode, lRoleKeys[t], changes)
|
||||
}
|
||||
}
|
||||
}
|
||||
for t = range rRoleKeys {
|
||||
if t < len(lRoleKeys) {
|
||||
if _, ok := lRoleValues[rRoleKeys[t]]; !ok {
|
||||
addedSecurityRequirement(rRoleValues[rRoleKeys[t]].ValueNode, rRoleKeys[t], changes)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if t >= len(lRoleKeys) {
|
||||
addedSecurityRequirement(rRoleValues[rRoleKeys[t]].ValueNode, rRoleKeys[t], changes)
|
||||
}
|
||||
}
|
||||
for t = range lRoleKeys {
|
||||
if t < len(rRoleKeys) {
|
||||
if _, ok := rRoleValues[lRoleKeys[t]]; !ok {
|
||||
removedSecurityRequirement(lRoleValues[lRoleKeys[t]].ValueNode, lRoleKeys[t], changes)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if t >= len(rRoleKeys) {
|
||||
if _, ok := rRoleValues[lRoleKeys[t]]; !ok {
|
||||
removedSecurityRequirement(lRoleValues[lRoleKeys[t]].ValueNode, lRoleKeys[t], changes)
|
||||
}
|
||||
}
|
||||
}
|
||||
for t = range rRoleKeys {
|
||||
if t < len(lRoleKeys) {
|
||||
if _, ok := lRoleValues[rRoleKeys[t]]; !ok {
|
||||
addedSecurityRequirement(rRoleValues[rRoleKeys[t]].ValueNode, rRoleKeys[t], changes)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if t >= len(lRoleKeys) {
|
||||
addedSecurityRequirement(rRoleValues[rRoleKeys[t]].ValueNode, rRoleKeys[t], changes)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if z >= len(rKeys) {
|
||||
if _, ok := rValues[lKeys[z]]; !ok {
|
||||
removedSecurityRequirement(lValues[lKeys[z]].ValueNode, lKeys[z], changes)
|
||||
}
|
||||
}
|
||||
}
|
||||
for z = range rKeys {
|
||||
if z < len(lKeys) {
|
||||
if _, ok := lValues[rKeys[z]]; !ok {
|
||||
addedSecurityRequirement(rValues[rKeys[z]].ValueNode, rKeys[z], changes)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if z >= len(lKeys) {
|
||||
if _, ok := lValues[rKeys[z]]; !ok {
|
||||
addedSecurityRequirement(rValues[rKeys[z]].ValueNode, rKeys[z], changes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if z >= len(rKeys) {
|
||||
if _, ok := rValues[lKeys[z]]; !ok {
|
||||
removedSecurityRequirement(lValues[lKeys[z]].ValueNode, lKeys[z], changes)
|
||||
}
|
||||
}
|
||||
}
|
||||
for z = range rKeys {
|
||||
if z < len(lKeys) {
|
||||
if _, ok := lValues[rKeys[z]]; !ok {
|
||||
addedSecurityRequirement(rValues[rKeys[z]].ValueNode, rKeys[z], changes)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if z >= len(lKeys) {
|
||||
if _, ok := lValues[rKeys[z]]; !ok {
|
||||
addedSecurityRequirement(rValues[rKeys[z]].ValueNode, rKeys[z], changes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,178 +4,178 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"reflect"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// SecuritySchemeChanges represents changes made between Swagger or OpenAPI SecurityScheme Objects.
|
||||
type SecuritySchemeChanges struct {
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
|
||||
// OpenAPI Version
|
||||
OAuthFlowChanges *OAuthFlowsChanges `json:"oAuthFlow,omitempty" yaml:"oAuthFlow,omitempty"`
|
||||
// OpenAPI Version
|
||||
OAuthFlowChanges *OAuthFlowsChanges `json:"oAuthFlow,omitempty" yaml:"oAuthFlow,omitempty"`
|
||||
|
||||
// Swagger Version
|
||||
ScopesChanges *ScopesChanges `json:"scopes,omitempty" yaml:"scopes,omitempty"`
|
||||
// Swagger Version
|
||||
ScopesChanges *ScopesChanges `json:"scopes,omitempty" yaml:"scopes,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between SecurityRequirement objects
|
||||
func (ss *SecuritySchemeChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, ss.Changes...)
|
||||
if ss.OAuthFlowChanges != nil {
|
||||
changes = append(changes, ss.OAuthFlowChanges.GetAllChanges()...)
|
||||
}
|
||||
if ss.ScopesChanges != nil {
|
||||
changes = append(changes, ss.ScopesChanges.GetAllChanges()...)
|
||||
}
|
||||
if ss.ExtensionChanges != nil {
|
||||
changes = append(changes, ss.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, ss.Changes...)
|
||||
if ss.OAuthFlowChanges != nil {
|
||||
changes = append(changes, ss.OAuthFlowChanges.GetAllChanges()...)
|
||||
}
|
||||
if ss.ScopesChanges != nil {
|
||||
changes = append(changes, ss.ScopesChanges.GetAllChanges()...)
|
||||
}
|
||||
if ss.ExtensionChanges != nil {
|
||||
changes = append(changes, ss.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges represents total changes found between two Swagger or OpenAPI SecurityScheme instances.
|
||||
func (ss *SecuritySchemeChanges) TotalChanges() int {
|
||||
c := ss.PropertyChanges.TotalChanges()
|
||||
if ss.OAuthFlowChanges != nil {
|
||||
c += ss.OAuthFlowChanges.TotalChanges()
|
||||
}
|
||||
if ss.ScopesChanges != nil {
|
||||
c += ss.ScopesChanges.TotalChanges()
|
||||
}
|
||||
if ss.ExtensionChanges != nil {
|
||||
c += ss.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := ss.PropertyChanges.TotalChanges()
|
||||
if ss.OAuthFlowChanges != nil {
|
||||
c += ss.OAuthFlowChanges.TotalChanges()
|
||||
}
|
||||
if ss.ScopesChanges != nil {
|
||||
c += ss.ScopesChanges.TotalChanges()
|
||||
}
|
||||
if ss.ExtensionChanges != nil {
|
||||
c += ss.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns total number of breaking changes between two SecurityScheme Objects.
|
||||
func (ss *SecuritySchemeChanges) TotalBreakingChanges() int {
|
||||
c := ss.PropertyChanges.TotalBreakingChanges()
|
||||
if ss.OAuthFlowChanges != nil {
|
||||
c += ss.OAuthFlowChanges.TotalBreakingChanges()
|
||||
}
|
||||
if ss.ScopesChanges != nil {
|
||||
c += ss.ScopesChanges.TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
c := ss.PropertyChanges.TotalBreakingChanges()
|
||||
if ss.OAuthFlowChanges != nil {
|
||||
c += ss.OAuthFlowChanges.TotalBreakingChanges()
|
||||
}
|
||||
if ss.ScopesChanges != nil {
|
||||
c += ss.ScopesChanges.TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CompareSecuritySchemesV2 is a Swagger type safe proxy for CompareSecuritySchemes
|
||||
func CompareSecuritySchemesV2(l, r *v2.SecurityScheme) *SecuritySchemeChanges {
|
||||
return CompareSecuritySchemes(l, r)
|
||||
return CompareSecuritySchemes(l, r)
|
||||
}
|
||||
|
||||
// CompareSecuritySchemesV3 is an OpenAPI type safe proxt for CompareSecuritySchemes
|
||||
func CompareSecuritySchemesV3(l, r *v3.SecurityScheme) *SecuritySchemeChanges {
|
||||
return CompareSecuritySchemes(l, r)
|
||||
return CompareSecuritySchemes(l, r)
|
||||
}
|
||||
|
||||
// CompareSecuritySchemes compares left and right Swagger or OpenAPI Security Scheme objects for changes.
|
||||
// If anything is found, returns a pointer to *SecuritySchemeChanges or nil if nothing is found.
|
||||
func CompareSecuritySchemes(l, r any) *SecuritySchemeChanges {
|
||||
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
|
||||
sc := new(SecuritySchemeChanges)
|
||||
if reflect.TypeOf(&v2.SecurityScheme{}) == reflect.TypeOf(l) &&
|
||||
reflect.TypeOf(&v2.SecurityScheme{}) == reflect.TypeOf(r) {
|
||||
sc := new(SecuritySchemeChanges)
|
||||
if reflect.TypeOf(&v2.SecurityScheme{}) == reflect.TypeOf(l) &&
|
||||
reflect.TypeOf(&v2.SecurityScheme{}) == reflect.TypeOf(r) {
|
||||
|
||||
lSS := l.(*v2.SecurityScheme)
|
||||
rSS := r.(*v2.SecurityScheme)
|
||||
lSS := l.(*v2.SecurityScheme)
|
||||
rSS := r.(*v2.SecurityScheme)
|
||||
|
||||
if low.AreEqual(lSS, rSS) {
|
||||
return nil
|
||||
}
|
||||
addPropertyCheck(&props, lSS.Type.ValueNode, rSS.Type.ValueNode,
|
||||
lSS.Type.Value, rSS.Type.Value, &changes, v3.TypeLabel, true)
|
||||
if low.AreEqual(lSS, rSS) {
|
||||
return nil
|
||||
}
|
||||
addPropertyCheck(&props, lSS.Type.ValueNode, rSS.Type.ValueNode,
|
||||
lSS.Type.Value, rSS.Type.Value, &changes, v3.TypeLabel, true)
|
||||
|
||||
addPropertyCheck(&props, lSS.Description.ValueNode, rSS.Description.ValueNode,
|
||||
lSS.Description.Value, rSS.Description.Value, &changes, v3.DescriptionLabel, false)
|
||||
addPropertyCheck(&props, lSS.Description.ValueNode, rSS.Description.ValueNode,
|
||||
lSS.Description.Value, rSS.Description.Value, &changes, v3.DescriptionLabel, false)
|
||||
|
||||
addPropertyCheck(&props, lSS.Name.ValueNode, rSS.Name.ValueNode,
|
||||
lSS.Name.Value, rSS.Name.Value, &changes, v3.NameLabel, true)
|
||||
addPropertyCheck(&props, lSS.Name.ValueNode, rSS.Name.ValueNode,
|
||||
lSS.Name.Value, rSS.Name.Value, &changes, v3.NameLabel, true)
|
||||
|
||||
addPropertyCheck(&props, lSS.In.ValueNode, rSS.In.ValueNode,
|
||||
lSS.In.Value, rSS.In.Value, &changes, v3.InLabel, true)
|
||||
addPropertyCheck(&props, lSS.In.ValueNode, rSS.In.ValueNode,
|
||||
lSS.In.Value, rSS.In.Value, &changes, v3.InLabel, true)
|
||||
|
||||
addPropertyCheck(&props, lSS.Flow.ValueNode, rSS.Flow.ValueNode,
|
||||
lSS.Flow.Value, rSS.Flow.Value, &changes, v3.FlowLabel, true)
|
||||
addPropertyCheck(&props, lSS.Flow.ValueNode, rSS.Flow.ValueNode,
|
||||
lSS.Flow.Value, rSS.Flow.Value, &changes, v3.FlowLabel, true)
|
||||
|
||||
addPropertyCheck(&props, lSS.AuthorizationUrl.ValueNode, rSS.AuthorizationUrl.ValueNode,
|
||||
lSS.AuthorizationUrl.Value, rSS.AuthorizationUrl.Value, &changes, v3.AuthorizationUrlLabel, true)
|
||||
addPropertyCheck(&props, lSS.AuthorizationUrl.ValueNode, rSS.AuthorizationUrl.ValueNode,
|
||||
lSS.AuthorizationUrl.Value, rSS.AuthorizationUrl.Value, &changes, v3.AuthorizationUrlLabel, true)
|
||||
|
||||
addPropertyCheck(&props, lSS.TokenUrl.ValueNode, rSS.TokenUrl.ValueNode,
|
||||
lSS.TokenUrl.Value, rSS.TokenUrl.Value, &changes, v3.TokenUrlLabel, true)
|
||||
addPropertyCheck(&props, lSS.TokenUrl.ValueNode, rSS.TokenUrl.ValueNode,
|
||||
lSS.TokenUrl.Value, rSS.TokenUrl.Value, &changes, v3.TokenUrlLabel, true)
|
||||
|
||||
if !lSS.Scopes.IsEmpty() && !rSS.Scopes.IsEmpty() {
|
||||
if !low.AreEqual(lSS.Scopes.Value, rSS.Scopes.Value) {
|
||||
sc.ScopesChanges = CompareScopes(lSS.Scopes.Value, rSS.Scopes.Value)
|
||||
}
|
||||
}
|
||||
if lSS.Scopes.IsEmpty() && !rSS.Scopes.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.ScopesLabel,
|
||||
nil, rSS.Scopes.ValueNode, false, nil, rSS.Scopes.Value)
|
||||
}
|
||||
if !lSS.Scopes.IsEmpty() && rSS.Scopes.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.ScopesLabel,
|
||||
lSS.Scopes.ValueNode, nil, true, lSS.Scopes.Value, nil)
|
||||
}
|
||||
if !lSS.Scopes.IsEmpty() && !rSS.Scopes.IsEmpty() {
|
||||
if !low.AreEqual(lSS.Scopes.Value, rSS.Scopes.Value) {
|
||||
sc.ScopesChanges = CompareScopes(lSS.Scopes.Value, rSS.Scopes.Value)
|
||||
}
|
||||
}
|
||||
if lSS.Scopes.IsEmpty() && !rSS.Scopes.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.ScopesLabel,
|
||||
nil, rSS.Scopes.ValueNode, false, nil, rSS.Scopes.Value)
|
||||
}
|
||||
if !lSS.Scopes.IsEmpty() && rSS.Scopes.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.ScopesLabel,
|
||||
lSS.Scopes.ValueNode, nil, true, lSS.Scopes.Value, nil)
|
||||
}
|
||||
|
||||
sc.ExtensionChanges = CompareExtensions(lSS.Extensions, rSS.Extensions)
|
||||
}
|
||||
sc.ExtensionChanges = CompareExtensions(lSS.Extensions, rSS.Extensions)
|
||||
}
|
||||
|
||||
if reflect.TypeOf(&v3.SecurityScheme{}) == reflect.TypeOf(l) &&
|
||||
reflect.TypeOf(&v3.SecurityScheme{}) == reflect.TypeOf(r) {
|
||||
if reflect.TypeOf(&v3.SecurityScheme{}) == reflect.TypeOf(l) &&
|
||||
reflect.TypeOf(&v3.SecurityScheme{}) == reflect.TypeOf(r) {
|
||||
|
||||
lSS := l.(*v3.SecurityScheme)
|
||||
rSS := r.(*v3.SecurityScheme)
|
||||
lSS := l.(*v3.SecurityScheme)
|
||||
rSS := r.(*v3.SecurityScheme)
|
||||
|
||||
if low.AreEqual(lSS, rSS) {
|
||||
return nil
|
||||
}
|
||||
addPropertyCheck(&props, lSS.Type.ValueNode, rSS.Type.ValueNode,
|
||||
lSS.Type.Value, rSS.Type.Value, &changes, v3.TypeLabel, true)
|
||||
if low.AreEqual(lSS, rSS) {
|
||||
return nil
|
||||
}
|
||||
addPropertyCheck(&props, lSS.Type.ValueNode, rSS.Type.ValueNode,
|
||||
lSS.Type.Value, rSS.Type.Value, &changes, v3.TypeLabel, true)
|
||||
|
||||
addPropertyCheck(&props, lSS.Description.ValueNode, rSS.Description.ValueNode,
|
||||
lSS.Description.Value, rSS.Description.Value, &changes, v3.DescriptionLabel, false)
|
||||
addPropertyCheck(&props, lSS.Description.ValueNode, rSS.Description.ValueNode,
|
||||
lSS.Description.Value, rSS.Description.Value, &changes, v3.DescriptionLabel, false)
|
||||
|
||||
addPropertyCheck(&props, lSS.Name.ValueNode, rSS.Name.ValueNode,
|
||||
lSS.Name.Value, rSS.Name.Value, &changes, v3.NameLabel, true)
|
||||
addPropertyCheck(&props, lSS.Name.ValueNode, rSS.Name.ValueNode,
|
||||
lSS.Name.Value, rSS.Name.Value, &changes, v3.NameLabel, true)
|
||||
|
||||
addPropertyCheck(&props, lSS.In.ValueNode, rSS.In.ValueNode,
|
||||
lSS.In.Value, rSS.In.Value, &changes, v3.InLabel, true)
|
||||
addPropertyCheck(&props, lSS.In.ValueNode, rSS.In.ValueNode,
|
||||
lSS.In.Value, rSS.In.Value, &changes, v3.InLabel, true)
|
||||
|
||||
addPropertyCheck(&props, lSS.Scheme.ValueNode, rSS.Scheme.ValueNode,
|
||||
lSS.Scheme.Value, rSS.Scheme.Value, &changes, v3.SchemeLabel, true)
|
||||
addPropertyCheck(&props, lSS.Scheme.ValueNode, rSS.Scheme.ValueNode,
|
||||
lSS.Scheme.Value, rSS.Scheme.Value, &changes, v3.SchemeLabel, true)
|
||||
|
||||
addPropertyCheck(&props, lSS.BearerFormat.ValueNode, rSS.BearerFormat.ValueNode,
|
||||
lSS.BearerFormat.Value, rSS.BearerFormat.Value, &changes, v3.SchemeLabel, false)
|
||||
addPropertyCheck(&props, lSS.BearerFormat.ValueNode, rSS.BearerFormat.ValueNode,
|
||||
lSS.BearerFormat.Value, rSS.BearerFormat.Value, &changes, v3.SchemeLabel, false)
|
||||
|
||||
addPropertyCheck(&props, lSS.OpenIdConnectUrl.ValueNode, rSS.OpenIdConnectUrl.ValueNode,
|
||||
lSS.OpenIdConnectUrl.Value, rSS.OpenIdConnectUrl.Value, &changes, v3.OpenIdConnectUrlLabel, false)
|
||||
addPropertyCheck(&props, lSS.OpenIdConnectUrl.ValueNode, rSS.OpenIdConnectUrl.ValueNode,
|
||||
lSS.OpenIdConnectUrl.Value, rSS.OpenIdConnectUrl.Value, &changes, v3.OpenIdConnectUrlLabel, false)
|
||||
|
||||
if !lSS.Flows.IsEmpty() && !rSS.Flows.IsEmpty() {
|
||||
if !low.AreEqual(lSS.Flows.Value, rSS.Flows.Value) {
|
||||
sc.OAuthFlowChanges = CompareOAuthFlows(lSS.Flows.Value, rSS.Flows.Value)
|
||||
}
|
||||
}
|
||||
if lSS.Flows.IsEmpty() && !rSS.Flows.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.FlowsLabel,
|
||||
nil, rSS.Flows.ValueNode, false, nil, rSS.Flows.Value)
|
||||
}
|
||||
if !lSS.Flows.IsEmpty() && rSS.Flows.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.ScopesLabel,
|
||||
lSS.Flows.ValueNode, nil, true, lSS.Flows.Value, nil)
|
||||
}
|
||||
sc.ExtensionChanges = CompareExtensions(lSS.Extensions, rSS.Extensions)
|
||||
}
|
||||
CheckProperties(props)
|
||||
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return sc
|
||||
if !lSS.Flows.IsEmpty() && !rSS.Flows.IsEmpty() {
|
||||
if !low.AreEqual(lSS.Flows.Value, rSS.Flows.Value) {
|
||||
sc.OAuthFlowChanges = CompareOAuthFlows(lSS.Flows.Value, rSS.Flows.Value)
|
||||
}
|
||||
}
|
||||
if lSS.Flows.IsEmpty() && !rSS.Flows.IsEmpty() {
|
||||
CreateChange(&changes, ObjectAdded, v3.FlowsLabel,
|
||||
nil, rSS.Flows.ValueNode, false, nil, rSS.Flows.Value)
|
||||
}
|
||||
if !lSS.Flows.IsEmpty() && rSS.Flows.IsEmpty() {
|
||||
CreateChange(&changes, ObjectRemoved, v3.ScopesLabel,
|
||||
lSS.Flows.ValueNode, nil, true, lSS.Flows.Value, nil)
|
||||
}
|
||||
sc.ExtensionChanges = CompareExtensions(lSS.Extensions, rSS.Extensions)
|
||||
}
|
||||
CheckProperties(props)
|
||||
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return sc
|
||||
}
|
||||
|
||||
@@ -4,79 +4,79 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// ServerChanges represents changes found between two OpenAPI Server Objects
|
||||
type ServerChanges struct {
|
||||
*PropertyChanges
|
||||
ServerVariableChanges map[string]*ServerVariableChanges `json:"serverVariables,omitempty" yaml:"serverVariables,omitempty"`
|
||||
*PropertyChanges
|
||||
ServerVariableChanges map[string]*ServerVariableChanges `json:"serverVariables,omitempty" yaml:"serverVariables,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between SecurityRequirement objects
|
||||
func (s *ServerChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, s.Changes...)
|
||||
for k := range s.ServerVariableChanges {
|
||||
changes = append(changes, s.ServerVariableChanges[k].GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, s.Changes...)
|
||||
for k := range s.ServerVariableChanges {
|
||||
changes = append(changes, s.ServerVariableChanges[k].GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns total changes found between two OpenAPI Server Objects
|
||||
func (s *ServerChanges) TotalChanges() int {
|
||||
c := s.PropertyChanges.TotalChanges()
|
||||
for k := range s.ServerVariableChanges {
|
||||
c += s.ServerVariableChanges[k].TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := s.PropertyChanges.TotalChanges()
|
||||
for k := range s.ServerVariableChanges {
|
||||
c += s.ServerVariableChanges[k].TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the total number of breaking changes found between two OpenAPI Server objects.
|
||||
func (s *ServerChanges) TotalBreakingChanges() int {
|
||||
c := s.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range s.ServerVariableChanges {
|
||||
c += s.ServerVariableChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
c := s.PropertyChanges.TotalBreakingChanges()
|
||||
for k := range s.ServerVariableChanges {
|
||||
c += s.ServerVariableChanges[k].TotalBreakingChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CompareServers compares two OpenAPI Server objects for any changes. If anything is found, returns a pointer
|
||||
// to a ServerChanges instance, or returns nil if nothing is found.
|
||||
func CompareServers(l, r *v3.Server) *ServerChanges {
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
|
||||
// URL
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.URL.ValueNode,
|
||||
RightNode: r.URL.ValueNode,
|
||||
Label: v3.URLLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// Description
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Description.ValueNode,
|
||||
RightNode: r.Description.ValueNode,
|
||||
Label: v3.DescriptionLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// URL
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.URL.ValueNode,
|
||||
RightNode: r.URL.ValueNode,
|
||||
Label: v3.URLLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// Description
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Description.ValueNode,
|
||||
RightNode: r.Description.ValueNode,
|
||||
Label: v3.DescriptionLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
CheckProperties(props)
|
||||
sc := new(ServerChanges)
|
||||
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||
sc.ServerVariableChanges = CheckMapForChanges(l.Variables.Value, r.Variables.Value,
|
||||
&changes, v3.VariablesLabel, CompareServerVariables)
|
||||
CheckProperties(props)
|
||||
sc := new(ServerChanges)
|
||||
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||
sc.ServerVariableChanges = CheckMapForChanges(l.Variables.Value, r.Variables.Value,
|
||||
&changes, v3.VariablesLabel, CompareServerVariables)
|
||||
|
||||
return sc
|
||||
return sc
|
||||
}
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompareServers(t *testing.T) {
|
||||
|
||||
left := `url: https://pb33f.io
|
||||
left := `url: https://pb33f.io
|
||||
description: a server
|
||||
variables:
|
||||
thing:
|
||||
@@ -22,7 +22,7 @@ variables:
|
||||
- biccy
|
||||
default: choccy`
|
||||
|
||||
right := `url: https://pb33f.io
|
||||
right := `url: https://pb33f.io
|
||||
description: a server
|
||||
variables:
|
||||
thing:
|
||||
@@ -31,26 +31,26 @@ variables:
|
||||
- biccy
|
||||
default: choccy`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.Server
|
||||
var rDoc v3.Server
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.Server
|
||||
var rDoc v3.Server
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareServers(&lDoc, &rDoc)
|
||||
assert.Nil(t, extChanges)
|
||||
// compare.
|
||||
extChanges := CompareServers(&lDoc, &rDoc)
|
||||
assert.Nil(t, extChanges)
|
||||
}
|
||||
|
||||
func TestCompareServers_Modified(t *testing.T) {
|
||||
|
||||
left := `url: https://pb33f.io
|
||||
left := `url: https://pb33f.io
|
||||
description: a server
|
||||
variables:
|
||||
thing:
|
||||
@@ -59,7 +59,7 @@ variables:
|
||||
- biccy
|
||||
default: choccy`
|
||||
|
||||
right := `url: https://pb33f.io/hotness
|
||||
right := `url: https://pb33f.io/hotness
|
||||
description: a server that is not
|
||||
variables:
|
||||
thing:
|
||||
@@ -68,27 +68,27 @@ variables:
|
||||
- biccy
|
||||
default: biccy`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.Server
|
||||
var rDoc v3.Server
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.Server
|
||||
var rDoc v3.Server
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareServers(&lDoc, &rDoc)
|
||||
assert.Equal(t, 3, extChanges.TotalChanges())
|
||||
// compare.
|
||||
extChanges := CompareServers(&lDoc, &rDoc)
|
||||
assert.Equal(t, 3, extChanges.TotalChanges())
|
||||
|
||||
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
|
||||
}
|
||||
|
||||
func TestCompareServers_Added(t *testing.T) {
|
||||
left := `url: https://pb33f.io
|
||||
left := `url: https://pb33f.io
|
||||
variables:
|
||||
thing:
|
||||
enum:
|
||||
@@ -96,7 +96,7 @@ variables:
|
||||
- biccy
|
||||
default: choccy`
|
||||
|
||||
right := `url: https://pb33f.io
|
||||
right := `url: https://pb33f.io
|
||||
description: a server
|
||||
variables:
|
||||
thing:
|
||||
@@ -106,29 +106,29 @@ variables:
|
||||
- tea
|
||||
default: choccy`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.Server
|
||||
var rDoc v3.Server
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.Server
|
||||
var rDoc v3.Server
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareServers(&lDoc, &rDoc)
|
||||
assert.Equal(t, 2, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 2)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, ObjectAdded, extChanges.ServerVariableChanges["thing"].Changes[0].ChangeType)
|
||||
// compare.
|
||||
extChanges := CompareServers(&lDoc, &rDoc)
|
||||
assert.Equal(t, 2, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 2)
|
||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, ObjectAdded, extChanges.ServerVariableChanges["thing"].Changes[0].ChangeType)
|
||||
}
|
||||
|
||||
func TestCompareServers_Removed(t *testing.T) {
|
||||
left := `url: https://pb33f.io
|
||||
left := `url: https://pb33f.io
|
||||
variables:
|
||||
thing:
|
||||
enum:
|
||||
@@ -136,7 +136,7 @@ variables:
|
||||
- biccy
|
||||
default: choccy`
|
||||
|
||||
right := `url: https://pb33f.io
|
||||
right := `url: https://pb33f.io
|
||||
description: a server
|
||||
variables:
|
||||
thing:
|
||||
@@ -146,23 +146,23 @@ variables:
|
||||
- tea
|
||||
default: choccy`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc v3.Server
|
||||
var rDoc v3.Server
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc v3.Server
|
||||
var rDoc v3.Server
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareServers(&rDoc, &lDoc)
|
||||
assert.Equal(t, 2, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 2)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, ObjectRemoved, extChanges.ServerVariableChanges["thing"].Changes[0].ChangeType)
|
||||
// compare.
|
||||
extChanges := CompareServers(&rDoc, &lDoc)
|
||||
assert.Equal(t, 2, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 2)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, ObjectRemoved, extChanges.ServerVariableChanges["thing"].Changes[0].ChangeType)
|
||||
}
|
||||
|
||||
@@ -4,79 +4,79 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// ServerVariableChanges represents changes found between two OpenAPI ServerVariable Objects
|
||||
type ServerVariableChanges struct {
|
||||
*PropertyChanges
|
||||
*PropertyChanges
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between SecurityRequirement objects
|
||||
func (s *ServerVariableChanges) GetAllChanges() []*Change {
|
||||
return s.Changes
|
||||
return s.Changes
|
||||
}
|
||||
|
||||
// CompareServerVariables compares a left and right OpenAPI ServerVariable object for changes.
|
||||
// If anything is found, returns a pointer to a ServerVariableChanges instance, otherwise returns nil.
|
||||
func CompareServerVariables(l, r *v3.ServerVariable) *ServerVariableChanges {
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
if low.AreEqual(l, r) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
var changes []*Change
|
||||
|
||||
lValues := make(map[string]low.NodeReference[string])
|
||||
rValues := make(map[string]low.NodeReference[string])
|
||||
for i := range l.Enum {
|
||||
lValues[l.Enum[i].Value] = l.Enum[i]
|
||||
}
|
||||
for i := range r.Enum {
|
||||
rValues[r.Enum[i].Value] = r.Enum[i]
|
||||
}
|
||||
for k := range lValues {
|
||||
if _, ok := rValues[k]; !ok {
|
||||
CreateChange(&changes, ObjectRemoved, v3.EnumLabel,
|
||||
lValues[k].ValueNode, nil, true,
|
||||
lValues[k].Value, nil)
|
||||
continue
|
||||
}
|
||||
}
|
||||
for k := range rValues {
|
||||
if _, ok := lValues[k]; !ok {
|
||||
CreateChange(&changes, ObjectAdded, v3.EnumLabel,
|
||||
lValues[k].ValueNode, rValues[k].ValueNode, false,
|
||||
lValues[k].Value, rValues[k].Value)
|
||||
}
|
||||
}
|
||||
lValues := make(map[string]low.NodeReference[string])
|
||||
rValues := make(map[string]low.NodeReference[string])
|
||||
for i := range l.Enum {
|
||||
lValues[l.Enum[i].Value] = l.Enum[i]
|
||||
}
|
||||
for i := range r.Enum {
|
||||
rValues[r.Enum[i].Value] = r.Enum[i]
|
||||
}
|
||||
for k := range lValues {
|
||||
if _, ok := rValues[k]; !ok {
|
||||
CreateChange(&changes, ObjectRemoved, v3.EnumLabel,
|
||||
lValues[k].ValueNode, nil, true,
|
||||
lValues[k].Value, nil)
|
||||
continue
|
||||
}
|
||||
}
|
||||
for k := range rValues {
|
||||
if _, ok := lValues[k]; !ok {
|
||||
CreateChange(&changes, ObjectAdded, v3.EnumLabel,
|
||||
lValues[k].ValueNode, rValues[k].ValueNode, false,
|
||||
lValues[k].Value, rValues[k].Value)
|
||||
}
|
||||
}
|
||||
|
||||
// default
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Default.ValueNode,
|
||||
RightNode: r.Default.ValueNode,
|
||||
Label: v3.DefaultLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// default
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Default.ValueNode,
|
||||
RightNode: r.Default.ValueNode,
|
||||
Label: v3.DefaultLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// description
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Description.ValueNode,
|
||||
RightNode: r.Description.ValueNode,
|
||||
Label: v3.DescriptionLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// description
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Description.ValueNode,
|
||||
RightNode: r.Description.ValueNode,
|
||||
Label: v3.DescriptionLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// check everything.
|
||||
CheckProperties(props)
|
||||
sc := new(ServerVariableChanges)
|
||||
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return sc
|
||||
// check everything.
|
||||
CheckProperties(props)
|
||||
sc := new(ServerVariableChanges)
|
||||
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||
return sc
|
||||
}
|
||||
|
||||
@@ -4,46 +4,46 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// TagChanges represents changes made to the Tags object of an OpenAPI document.
|
||||
type TagChanges struct {
|
||||
*PropertyChanges
|
||||
ExternalDocs *ExternalDocChanges `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
*PropertyChanges
|
||||
ExternalDocs *ExternalDocChanges `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between Tag objects
|
||||
func (t *TagChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, t.Changes...)
|
||||
if t.ExternalDocs != nil {
|
||||
changes = append(changes, t.ExternalDocs.GetAllChanges()...)
|
||||
}
|
||||
if t.ExtensionChanges != nil {
|
||||
changes = append(changes, t.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, t.Changes...)
|
||||
if t.ExternalDocs != nil {
|
||||
changes = append(changes, t.ExternalDocs.GetAllChanges()...)
|
||||
}
|
||||
if t.ExtensionChanges != nil {
|
||||
changes = append(changes, t.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns a count of everything that changed within tags.
|
||||
func (t *TagChanges) TotalChanges() int {
|
||||
c := t.PropertyChanges.TotalChanges()
|
||||
if t.ExternalDocs != nil {
|
||||
c += t.ExternalDocs.TotalChanges()
|
||||
}
|
||||
if t.ExtensionChanges != nil {
|
||||
c += t.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := t.PropertyChanges.TotalChanges()
|
||||
if t.ExternalDocs != nil {
|
||||
c += t.ExternalDocs.TotalChanges()
|
||||
}
|
||||
if t.ExtensionChanges != nil {
|
||||
c += t.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the number of breaking changes made by Tags
|
||||
func (t *TagChanges) TotalBreakingChanges() int {
|
||||
return t.PropertyChanges.TotalBreakingChanges()
|
||||
return t.PropertyChanges.TotalBreakingChanges()
|
||||
}
|
||||
|
||||
// CompareTags will compare a left (original) and a right (new) slice of ValueReference nodes for
|
||||
@@ -51,100 +51,100 @@ func (t *TagChanges) TotalBreakingChanges() int {
|
||||
// nil is returned instead.
|
||||
func CompareTags(l, r []low.ValueReference[*base.Tag]) []*TagChanges {
|
||||
|
||||
var tagResults []*TagChanges
|
||||
var tagResults []*TagChanges
|
||||
|
||||
// look at the original and then look through the new.
|
||||
seenLeft := make(map[string]*low.ValueReference[*base.Tag])
|
||||
seenRight := make(map[string]*low.ValueReference[*base.Tag])
|
||||
for i := range l {
|
||||
h := l[i]
|
||||
seenLeft[l[i].Value.Name.Value] = &h
|
||||
}
|
||||
for i := range r {
|
||||
h := r[i]
|
||||
seenRight[r[i].Value.Name.Value] = &h
|
||||
}
|
||||
// look at the original and then look through the new.
|
||||
seenLeft := make(map[string]*low.ValueReference[*base.Tag])
|
||||
seenRight := make(map[string]*low.ValueReference[*base.Tag])
|
||||
for i := range l {
|
||||
h := l[i]
|
||||
seenLeft[l[i].Value.Name.Value] = &h
|
||||
}
|
||||
for i := range r {
|
||||
h := r[i]
|
||||
seenRight[r[i].Value.Name.Value] = &h
|
||||
}
|
||||
|
||||
//var changes []*Change
|
||||
//var changes []*Change
|
||||
|
||||
// check for removals, modifications and moves
|
||||
for i := range seenLeft {
|
||||
tc := new(TagChanges)
|
||||
var changes []*Change
|
||||
// check for removals, modifications and moves
|
||||
for i := range seenLeft {
|
||||
tc := new(TagChanges)
|
||||
var changes []*Change
|
||||
|
||||
CheckForObjectAdditionOrRemoval[*base.Tag](seenLeft, seenRight, i, &changes, false, true)
|
||||
CheckForObjectAdditionOrRemoval[*base.Tag](seenLeft, seenRight, i, &changes, false, true)
|
||||
|
||||
// if the existing tag exists, let's check it.
|
||||
if seenRight[i] != nil {
|
||||
// if the existing tag exists, let's check it.
|
||||
if seenRight[i] != nil {
|
||||
|
||||
var props []*PropertyCheck
|
||||
var props []*PropertyCheck
|
||||
|
||||
// Name
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: seenLeft[i].Value.Name.ValueNode,
|
||||
RightNode: seenRight[i].Value.Name.ValueNode,
|
||||
Label: v3.NameLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: seenLeft[i].Value,
|
||||
New: seenRight[i].Value,
|
||||
})
|
||||
// Name
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: seenLeft[i].Value.Name.ValueNode,
|
||||
RightNode: seenRight[i].Value.Name.ValueNode,
|
||||
Label: v3.NameLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: seenLeft[i].Value,
|
||||
New: seenRight[i].Value,
|
||||
})
|
||||
|
||||
// Description
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: seenLeft[i].Value.Description.ValueNode,
|
||||
RightNode: seenRight[i].Value.Description.ValueNode,
|
||||
Label: v3.DescriptionLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: seenLeft[i].Value,
|
||||
New: seenRight[i].Value,
|
||||
})
|
||||
// Description
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: seenLeft[i].Value.Description.ValueNode,
|
||||
RightNode: seenRight[i].Value.Description.ValueNode,
|
||||
Label: v3.DescriptionLabel,
|
||||
Changes: &changes,
|
||||
Breaking: false,
|
||||
Original: seenLeft[i].Value,
|
||||
New: seenRight[i].Value,
|
||||
})
|
||||
|
||||
// check properties
|
||||
CheckProperties(props)
|
||||
// check properties
|
||||
CheckProperties(props)
|
||||
|
||||
// compare external docs
|
||||
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)
|
||||
}
|
||||
// compare external docs
|
||||
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 = CompareExtensions(seenLeft[i].Value.Extensions, seenRight[i].Value.Extensions)
|
||||
tc.PropertyChanges = NewPropertyChanges(changes)
|
||||
if tc.TotalChanges() > 0 {
|
||||
tagResults = append(tagResults, tc)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// check extensions
|
||||
tc.ExtensionChanges = CompareExtensions(seenLeft[i].Value.Extensions, seenRight[i].Value.Extensions)
|
||||
tc.PropertyChanges = NewPropertyChanges(changes)
|
||||
if tc.TotalChanges() > 0 {
|
||||
tagResults = append(tagResults, tc)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if len(changes) > 0 {
|
||||
tc.PropertyChanges = NewPropertyChanges(changes)
|
||||
tagResults = append(tagResults, tc)
|
||||
}
|
||||
if len(changes) > 0 {
|
||||
tc.PropertyChanges = NewPropertyChanges(changes)
|
||||
tagResults = append(tagResults, tc)
|
||||
}
|
||||
|
||||
}
|
||||
for i := range seenRight {
|
||||
if seenLeft[i] == nil {
|
||||
tc := new(TagChanges)
|
||||
var changes []*Change
|
||||
}
|
||||
for i := range seenRight {
|
||||
if seenLeft[i] == nil {
|
||||
tc := new(TagChanges)
|
||||
var changes []*Change
|
||||
|
||||
CreateChange(&changes, ObjectAdded, i, nil, seenRight[i].GetValueNode(),
|
||||
false, nil, seenRight[i].GetValue())
|
||||
CreateChange(&changes, ObjectAdded, i, nil, seenRight[i].GetValueNode(),
|
||||
false, nil, seenRight[i].GetValue())
|
||||
|
||||
tc.PropertyChanges = NewPropertyChanges(changes)
|
||||
tagResults = append(tagResults, tc)
|
||||
tc.PropertyChanges = NewPropertyChanges(changes)
|
||||
tagResults = append(tagResults, tc)
|
||||
|
||||
}
|
||||
}
|
||||
return tagResults
|
||||
}
|
||||
}
|
||||
return tagResults
|
||||
}
|
||||
|
||||
@@ -4,111 +4,111 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
)
|
||||
|
||||
// XMLChanges represents changes made to the XML object of an OpenAPI document.
|
||||
type XMLChanges struct {
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
*PropertyChanges
|
||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// GetAllChanges returns a slice of all changes made between XML objects
|
||||
func (x *XMLChanges) GetAllChanges() []*Change {
|
||||
var changes []*Change
|
||||
changes = append(changes, x.Changes...)
|
||||
if x.ExtensionChanges != nil {
|
||||
changes = append(changes, x.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
var changes []*Change
|
||||
changes = append(changes, x.Changes...)
|
||||
if x.ExtensionChanges != nil {
|
||||
changes = append(changes, x.ExtensionChanges.GetAllChanges()...)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
// TotalChanges returns a count of everything that was changed within an XML object.
|
||||
func (x *XMLChanges) TotalChanges() int {
|
||||
c := x.PropertyChanges.TotalChanges()
|
||||
if x.ExtensionChanges != nil {
|
||||
c += x.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
c := x.PropertyChanges.TotalChanges()
|
||||
if x.ExtensionChanges != nil {
|
||||
c += x.ExtensionChanges.TotalChanges()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// TotalBreakingChanges returns the number of breaking changes made by the XML object.
|
||||
func (x *XMLChanges) TotalBreakingChanges() int {
|
||||
return x.PropertyChanges.TotalBreakingChanges()
|
||||
return x.PropertyChanges.TotalBreakingChanges()
|
||||
}
|
||||
|
||||
// CompareXML will compare a left (original) and a right (new) XML instance, and check for
|
||||
// any changes between them. If changes are found, the function returns a pointer to XMLChanges,
|
||||
// otherwise, if nothing changed - it will return nil
|
||||
func CompareXML(l, r *base.XML) *XMLChanges {
|
||||
xc := new(XMLChanges)
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
xc := new(XMLChanges)
|
||||
var changes []*Change
|
||||
var props []*PropertyCheck
|
||||
|
||||
// Name (breaking change)
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Name.ValueNode,
|
||||
RightNode: r.Name.ValueNode,
|
||||
Label: v3.NameLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// Name (breaking change)
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Name.ValueNode,
|
||||
RightNode: r.Name.ValueNode,
|
||||
Label: v3.NameLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// Namespace (breaking change)
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Namespace.ValueNode,
|
||||
RightNode: r.Namespace.ValueNode,
|
||||
Label: v3.NamespaceLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// Namespace (breaking change)
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Namespace.ValueNode,
|
||||
RightNode: r.Namespace.ValueNode,
|
||||
Label: v3.NamespaceLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// Prefix (breaking change)
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Prefix.ValueNode,
|
||||
RightNode: r.Prefix.ValueNode,
|
||||
Label: v3.PrefixLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// Prefix (breaking change)
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Prefix.ValueNode,
|
||||
RightNode: r.Prefix.ValueNode,
|
||||
Label: v3.PrefixLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// Attribute (breaking change)
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Attribute.ValueNode,
|
||||
RightNode: r.Attribute.ValueNode,
|
||||
Label: v3.AttributeLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// Attribute (breaking change)
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Attribute.ValueNode,
|
||||
RightNode: r.Attribute.ValueNode,
|
||||
Label: v3.AttributeLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// Wrapped (breaking change)
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Wrapped.ValueNode,
|
||||
RightNode: r.Wrapped.ValueNode,
|
||||
Label: v3.WrappedLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
// Wrapped (breaking change)
|
||||
props = append(props, &PropertyCheck{
|
||||
LeftNode: l.Wrapped.ValueNode,
|
||||
RightNode: r.Wrapped.ValueNode,
|
||||
Label: v3.WrappedLabel,
|
||||
Changes: &changes,
|
||||
Breaking: true,
|
||||
Original: l,
|
||||
New: r,
|
||||
})
|
||||
|
||||
// check properties
|
||||
CheckProperties(props)
|
||||
// check properties
|
||||
CheckProperties(props)
|
||||
|
||||
// check extensions
|
||||
xc.ExtensionChanges = CheckExtensions(l, r)
|
||||
xc.PropertyChanges = NewPropertyChanges(changes)
|
||||
if xc.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return xc
|
||||
// check extensions
|
||||
xc.ExtensionChanges = CheckExtensions(l, r)
|
||||
xc.PropertyChanges = NewPropertyChanges(changes)
|
||||
if xc.TotalChanges() <= 0 {
|
||||
return nil
|
||||
}
|
||||
return xc
|
||||
}
|
||||
|
||||
@@ -4,144 +4,144 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
"github.com/pb33f/libopenapi/datamodel/low"
|
||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompareXML_NameChanged(t *testing.T) {
|
||||
|
||||
left := `name: xml thing
|
||||
left := `name: xml thing
|
||||
namespace: something
|
||||
prefix: another
|
||||
attribute: true
|
||||
wrapped: true`
|
||||
|
||||
right := `namespace: something
|
||||
right := `namespace: something
|
||||
prefix: another
|
||||
name: changed xml thing
|
||||
attribute: true
|
||||
wrapped: true`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.XML
|
||||
var rDoc base.XML
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.XML
|
||||
var rDoc base.XML
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareXML(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
|
||||
// compare.
|
||||
extChanges := CompareXML(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
|
||||
|
||||
}
|
||||
|
||||
func TestCompareXML_NameRemoved(t *testing.T) {
|
||||
|
||||
left := `name: xml thing
|
||||
left := `name: xml thing
|
||||
namespace: something
|
||||
prefix: another
|
||||
attribute: true
|
||||
wrapped: true`
|
||||
|
||||
right := `wrapped: true
|
||||
right := `wrapped: true
|
||||
prefix: another
|
||||
attribute: true
|
||||
namespace: something`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.XML
|
||||
var rDoc base.XML
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.XML
|
||||
var rDoc base.XML
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareXML(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
// compare.
|
||||
extChanges := CompareXML(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
|
||||
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||
|
||||
}
|
||||
|
||||
func TestCompareXML_ExtensionAdded(t *testing.T) {
|
||||
|
||||
left := `name: xml thing
|
||||
left := `name: xml thing
|
||||
namespace: something
|
||||
prefix: another
|
||||
attribute: true
|
||||
wrapped: true`
|
||||
|
||||
right := `name: xml thing
|
||||
right := `name: xml thing
|
||||
namespace: something
|
||||
prefix: another
|
||||
attribute: true
|
||||
wrapped: true
|
||||
x-coffee: time`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.XML
|
||||
var rDoc base.XML
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.XML
|
||||
var rDoc base.XML
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareXML(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, ObjectAdded, extChanges.ExtensionChanges.Changes[0].ChangeType)
|
||||
// compare.
|
||||
extChanges := CompareXML(&lDoc, &rDoc)
|
||||
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||
assert.Len(t, extChanges.GetAllChanges(), 1)
|
||||
assert.Equal(t, ObjectAdded, extChanges.ExtensionChanges.Changes[0].ChangeType)
|
||||
|
||||
}
|
||||
|
||||
func TestCompareXML_Identical(t *testing.T) {
|
||||
|
||||
left := `name: xml thing
|
||||
left := `name: xml thing
|
||||
namespace: something
|
||||
prefix: another
|
||||
attribute: true
|
||||
wrapped: true`
|
||||
|
||||
right := `name: xml thing
|
||||
right := `name: xml thing
|
||||
namespace: something
|
||||
prefix: another
|
||||
attribute: true
|
||||
wrapped: true`
|
||||
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
var lNode, rNode yaml.Node
|
||||
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||
|
||||
// create low level objects
|
||||
var lDoc base.XML
|
||||
var rDoc base.XML
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
// create low level objects
|
||||
var lDoc base.XML
|
||||
var rDoc base.XML
|
||||
_ = low.BuildModel(lNode.Content[0], &lDoc)
|
||||
_ = low.BuildModel(rNode.Content[0], &rDoc)
|
||||
_ = lDoc.Build(lNode.Content[0], nil)
|
||||
_ = rDoc.Build(rNode.Content[0], nil)
|
||||
|
||||
// compare.
|
||||
extChanges := CompareXML(&lDoc, &rDoc)
|
||||
// compare.
|
||||
extChanges := CompareXML(&lDoc, &rDoc)
|
||||
assert.Nil(t, extChanges)
|
||||
|
||||
}
|
||||
|
||||
@@ -4,85 +4,85 @@
|
||||
package reports
|
||||
|
||||
import (
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/what-changed/model"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/what-changed/model"
|
||||
)
|
||||
|
||||
// Changed provides a simple wrapper for changed counts
|
||||
type Changed struct {
|
||||
Total int `json:"totalChanges"`
|
||||
Breaking int `json:"breakingChanges"`
|
||||
Total int `json:"totalChanges"`
|
||||
Breaking int `json:"breakingChanges"`
|
||||
}
|
||||
|
||||
// OverallReport provides a Document level overview of all changes to an OpenAPI doc.
|
||||
type OverallReport struct {
|
||||
ChangeReport map[string]*Changed `json:"overallSummaryReport"`
|
||||
ChangeReport map[string]*Changed `json:"overallSummaryReport"`
|
||||
}
|
||||
|
||||
// CreateOverallReport will create a high level report for all top level changes (but with deep counts)
|
||||
func CreateOverallReport(changes *model.DocumentChanges) *OverallReport {
|
||||
|
||||
changedReport := make(map[string]*Changed)
|
||||
if changes.InfoChanges != nil {
|
||||
changedReport[v3.InfoLabel] = createChangedModel(changes.InfoChanges)
|
||||
}
|
||||
if changes.PathsChanges != nil {
|
||||
changedReport[v3.PathsLabel] = createChangedModel(changes.PathsChanges)
|
||||
}
|
||||
if changes.TagChanges != nil {
|
||||
j := make([]HasChanges, len(changes.TagChanges))
|
||||
for k := range changes.TagChanges {
|
||||
j[k] = HasChanges(changes.TagChanges[k])
|
||||
}
|
||||
changedReport[v3.TagsLabel] = createChangedModelFromSlice(j)
|
||||
}
|
||||
if changes.ExternalDocChanges != nil {
|
||||
changedReport[v3.ExternalDocsLabel] = createChangedModel(changes.ExternalDocChanges)
|
||||
}
|
||||
if changes.WebhookChanges != nil {
|
||||
j := make([]HasChanges, len(changes.WebhookChanges))
|
||||
z := 0
|
||||
for k := range changes.WebhookChanges {
|
||||
j[z] = HasChanges(changes.WebhookChanges[k])
|
||||
z++
|
||||
}
|
||||
ch := createChangedModelFromSlice(j)
|
||||
if ch.Total > 0 {
|
||||
changedReport[v3.WebhooksLabel] = ch
|
||||
}
|
||||
}
|
||||
if changes.ServerChanges != nil {
|
||||
j := make([]HasChanges, len(changes.ServerChanges))
|
||||
for k := range changes.ServerChanges {
|
||||
j[k] = HasChanges(changes.ServerChanges[k])
|
||||
}
|
||||
changedReport[v3.ServersLabel] = createChangedModelFromSlice(j)
|
||||
}
|
||||
if changes.SecurityRequirementChanges != nil {
|
||||
j := make([]HasChanges, len(changes.SecurityRequirementChanges))
|
||||
for k := range changes.SecurityRequirementChanges {
|
||||
j[k] = HasChanges(changes.SecurityRequirementChanges[k])
|
||||
}
|
||||
changedReport[v3.SecurityLabel] = createChangedModelFromSlice(j)
|
||||
}
|
||||
if changes.ComponentsChanges != nil {
|
||||
changedReport[v3.ComponentsLabel] = createChangedModel(changes.ComponentsChanges)
|
||||
}
|
||||
return &OverallReport{
|
||||
ChangeReport: changedReport,
|
||||
}
|
||||
changedReport := make(map[string]*Changed)
|
||||
if changes.InfoChanges != nil {
|
||||
changedReport[v3.InfoLabel] = createChangedModel(changes.InfoChanges)
|
||||
}
|
||||
if changes.PathsChanges != nil {
|
||||
changedReport[v3.PathsLabel] = createChangedModel(changes.PathsChanges)
|
||||
}
|
||||
if changes.TagChanges != nil {
|
||||
j := make([]HasChanges, len(changes.TagChanges))
|
||||
for k := range changes.TagChanges {
|
||||
j[k] = HasChanges(changes.TagChanges[k])
|
||||
}
|
||||
changedReport[v3.TagsLabel] = createChangedModelFromSlice(j)
|
||||
}
|
||||
if changes.ExternalDocChanges != nil {
|
||||
changedReport[v3.ExternalDocsLabel] = createChangedModel(changes.ExternalDocChanges)
|
||||
}
|
||||
if changes.WebhookChanges != nil {
|
||||
j := make([]HasChanges, len(changes.WebhookChanges))
|
||||
z := 0
|
||||
for k := range changes.WebhookChanges {
|
||||
j[z] = HasChanges(changes.WebhookChanges[k])
|
||||
z++
|
||||
}
|
||||
ch := createChangedModelFromSlice(j)
|
||||
if ch.Total > 0 {
|
||||
changedReport[v3.WebhooksLabel] = ch
|
||||
}
|
||||
}
|
||||
if changes.ServerChanges != nil {
|
||||
j := make([]HasChanges, len(changes.ServerChanges))
|
||||
for k := range changes.ServerChanges {
|
||||
j[k] = HasChanges(changes.ServerChanges[k])
|
||||
}
|
||||
changedReport[v3.ServersLabel] = createChangedModelFromSlice(j)
|
||||
}
|
||||
if changes.SecurityRequirementChanges != nil {
|
||||
j := make([]HasChanges, len(changes.SecurityRequirementChanges))
|
||||
for k := range changes.SecurityRequirementChanges {
|
||||
j[k] = HasChanges(changes.SecurityRequirementChanges[k])
|
||||
}
|
||||
changedReport[v3.SecurityLabel] = createChangedModelFromSlice(j)
|
||||
}
|
||||
if changes.ComponentsChanges != nil {
|
||||
changedReport[v3.ComponentsLabel] = createChangedModel(changes.ComponentsChanges)
|
||||
}
|
||||
return &OverallReport{
|
||||
ChangeReport: changedReport,
|
||||
}
|
||||
}
|
||||
|
||||
func createChangedModel(ch HasChanges) *Changed {
|
||||
return &Changed{ch.TotalChanges(), ch.TotalBreakingChanges()}
|
||||
return &Changed{ch.TotalChanges(), ch.TotalBreakingChanges()}
|
||||
}
|
||||
|
||||
func createChangedModelFromSlice(ch []HasChanges) *Changed {
|
||||
t := 0
|
||||
b := 0
|
||||
for n := range ch {
|
||||
t += ch[n].TotalChanges()
|
||||
b += ch[n].TotalBreakingChanges()
|
||||
}
|
||||
return &Changed{t, b}
|
||||
t := 0
|
||||
b := 0
|
||||
for n := range ch {
|
||||
t += ch[n].TotalChanges()
|
||||
b += ch[n].TotalBreakingChanges()
|
||||
}
|
||||
return &Changed{t, b}
|
||||
}
|
||||
|
||||
@@ -4,35 +4,35 @@
|
||||
package reports
|
||||
|
||||
import (
|
||||
"github.com/pb33f/libopenapi"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/what-changed/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"github.com/pb33f/libopenapi"
|
||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||
"github.com/pb33f/libopenapi/what-changed/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func createDiff() *model.DocumentChanges {
|
||||
burgerShopOriginal, _ := ioutil.ReadFile("../../test_specs/burgershop.openapi.yaml")
|
||||
burgerShopUpdated, _ := ioutil.ReadFile("../../test_specs/burgershop.openapi-modified.yaml")
|
||||
originalDoc, _ := libopenapi.NewDocument(burgerShopOriginal)
|
||||
updatedDoc, _ := libopenapi.NewDocument(burgerShopUpdated)
|
||||
documentChanges, _ := libopenapi.CompareDocuments(originalDoc, updatedDoc)
|
||||
return documentChanges
|
||||
burgerShopOriginal, _ := ioutil.ReadFile("../../test_specs/burgershop.openapi.yaml")
|
||||
burgerShopUpdated, _ := ioutil.ReadFile("../../test_specs/burgershop.openapi-modified.yaml")
|
||||
originalDoc, _ := libopenapi.NewDocument(burgerShopOriginal)
|
||||
updatedDoc, _ := libopenapi.NewDocument(burgerShopUpdated)
|
||||
documentChanges, _ := libopenapi.CompareDocuments(originalDoc, updatedDoc)
|
||||
return documentChanges
|
||||
}
|
||||
|
||||
func TestCreateSummary_OverallReport(t *testing.T) {
|
||||
changes := createDiff()
|
||||
report := CreateOverallReport(changes)
|
||||
assert.Equal(t, 1, report.ChangeReport[v3.InfoLabel].Total)
|
||||
assert.Equal(t, 43, report.ChangeReport[v3.PathsLabel].Total)
|
||||
assert.Equal(t, 9, report.ChangeReport[v3.PathsLabel].Breaking)
|
||||
assert.Equal(t, 3, report.ChangeReport[v3.TagsLabel].Total)
|
||||
assert.Equal(t, 1, report.ChangeReport[v3.ExternalDocsLabel].Total)
|
||||
assert.Equal(t, 2, report.ChangeReport[v3.WebhooksLabel].Total)
|
||||
assert.Equal(t, 2, report.ChangeReport[v3.ServersLabel].Total)
|
||||
assert.Equal(t, 1, report.ChangeReport[v3.ServersLabel].Breaking)
|
||||
assert.Equal(t, 1, report.ChangeReport[v3.SecurityLabel].Total)
|
||||
assert.Equal(t, 17, report.ChangeReport[v3.ComponentsLabel].Total)
|
||||
assert.Equal(t, 6, report.ChangeReport[v3.ComponentsLabel].Breaking)
|
||||
changes := createDiff()
|
||||
report := CreateOverallReport(changes)
|
||||
assert.Equal(t, 1, report.ChangeReport[v3.InfoLabel].Total)
|
||||
assert.Equal(t, 43, report.ChangeReport[v3.PathsLabel].Total)
|
||||
assert.Equal(t, 9, report.ChangeReport[v3.PathsLabel].Breaking)
|
||||
assert.Equal(t, 3, report.ChangeReport[v3.TagsLabel].Total)
|
||||
assert.Equal(t, 1, report.ChangeReport[v3.ExternalDocsLabel].Total)
|
||||
assert.Equal(t, 2, report.ChangeReport[v3.WebhooksLabel].Total)
|
||||
assert.Equal(t, 2, report.ChangeReport[v3.ServersLabel].Total)
|
||||
assert.Equal(t, 1, report.ChangeReport[v3.ServersLabel].Breaking)
|
||||
assert.Equal(t, 1, report.ChangeReport[v3.SecurityLabel].Total)
|
||||
assert.Equal(t, 17, report.ChangeReport[v3.ComponentsLabel].Total)
|
||||
assert.Equal(t, 6, report.ChangeReport[v3.ComponentsLabel].Breaking)
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ package reports
|
||||
// HasChanges represents a change model that provides a total change count and a breaking change count.
|
||||
type HasChanges interface {
|
||||
|
||||
// TotalChanges represents number of all changes found
|
||||
TotalChanges() int
|
||||
// TotalChanges represents number of all changes found
|
||||
TotalChanges() int
|
||||
|
||||
// TotalBreakingChanges represents the number of contract breaking changes only.
|
||||
TotalBreakingChanges() int
|
||||
// TotalBreakingChanges represents the number of contract breaking changes only.
|
||||
TotalBreakingChanges() int
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user