Large refactor and addedGetAllChanges to each change

tons of updates, so many things.
This commit is contained in:
Dave Shanley
2023-03-20 19:19:29 -04:00
parent 0e8ae7c548
commit 5189eadddc
91 changed files with 3483 additions and 715 deletions

View File

@@ -86,7 +86,7 @@ type Schema struct {
MinProperties *int64 `json:"minProperties,omitempty" yaml:"minProperties,omitempty"`
Required []string `json:"required,omitempty" yaml:"required,omitempty"`
Enum []any `json:"enum,omitempty" yaml:"enum,omitempty"`
AdditionalProperties any `json:"additionalProperties,omitempty" yaml:"additionalProperties,omitempty"`
AdditionalProperties any `json:"additionalProperties,omitempty" yaml:"additionalProperties,renderZero,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Default any `json:"default,omitempty" yaml:"default,omitempty"`
Nullable *bool `json:"nullable,omitempty" yaml:"nullable,omitempty"`
@@ -300,6 +300,7 @@ func NewSchema(schema *base.Schema) *Schema {
p := &SchemaProxy{schema: &lowmodel.NodeReference[*base.SchemaProxy]{
ValueNode: sch.ValueNode,
Value: sch.Value,
Reference: sch.GetReference(),
}}
bChan <- buildResult{idx: idx, s: p}

View File

@@ -1019,3 +1019,74 @@ func TestNewSchemaProxy_RenderSchemaCheckAdditionalPropertiesSliceMap(t *testing
assert.Len(t, schemaBytes, 75)
}
/*
*/
func TestNewSchemaProxy_RenderAdditionalPropertiesFalse(t *testing.T) {
testSpec := `additionalProperties: false`
var compNode yaml.Node
_ = yaml.Unmarshal([]byte(testSpec), &compNode)
sp := new(lowbase.SchemaProxy)
err := sp.Build(compNode.Content[0], nil)
assert.NoError(t, err)
lowproxy := low.NodeReference[*lowbase.SchemaProxy]{
Value: sp,
ValueNode: compNode.Content[0],
}
schemaProxy := NewSchemaProxy(&lowproxy)
compiled := schemaProxy.Schema()
// now render it out, it should be identical.
schemaBytes, _ := compiled.Render()
assert.Equal(t, testSpec, strings.TrimSpace(string(schemaBytes)))
}
func TestNewSchemaProxy_RenderMultiplePoly(t *testing.T) {
idxYaml := `openapi: 3.1.0
components:
schemas:
balance_transaction:
description: A balance transaction`
testSpec := `properties:
bigBank:
type: object
properties:
failure_balance_transaction:
anyOf:
- maxLength: 5000
type: string
- $ref: '#/components/schemas/balance_transaction'
x-expansionResources:
oneOf:
- $ref: '#/components/schemas/balance_transaction'`
var compNode, idxNode yaml.Node
_ = yaml.Unmarshal([]byte(testSpec), &compNode)
_ = yaml.Unmarshal([]byte(idxYaml), &idxNode)
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateOpenAPIIndexConfig())
sp := new(lowbase.SchemaProxy)
err := sp.Build(compNode.Content[0], idx)
assert.NoError(t, err)
lowproxy := low.NodeReference[*lowbase.SchemaProxy]{
Value: sp,
ValueNode: idxNode.Content[0],
}
sch1 := SchemaProxy{schema: &lowproxy}
compiled := sch1.Schema()
// now render it out, it should be identical.
schemaBytes, _ := compiled.Render()
assert.Equal(t, testSpec, strings.TrimSpace(string(schemaBytes)))
}

View File

@@ -4,12 +4,14 @@
package base
import (
"github.com/pb33f/libopenapi/datamodel/high"
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3"
"sort"
)
// SecurityRequirement is a high-level representation of a Swagger / OpenAPI 2 SecurityRequirement object.
// SecurityRequirement is a high-level representation of a Swagger / OpenAPI 3 SecurityRequirement object.
//
// SecurityRequirement lists the required security schemes to execute this operation. The object can have multiple
// security schemes declared in it which are all required (that is, there is a logical AND between the schemes).
@@ -17,7 +19,7 @@ import (
// The name used for each property MUST correspond to a security scheme declared in the Security Definitions
// - https://swagger.io/specification/v2/#securityDefinitionsObject
type SecurityRequirement struct {
Requirements map[string][]string
Requirements map[string][]string `json:"-" yaml:"-"`
low *base.SecurityRequirement
}
@@ -55,6 +57,69 @@ func (s *SecurityRequirement) Render() ([]byte, error) {
// MarshalYAML will create a ready to render YAML representation of the SecurityRequirement object.
func (s *SecurityRequirement) MarshalYAML() (interface{}, error) {
nb := high.NewNodeBuilder(s, s.low)
return nb.Render(), nil
type req struct {
line int
key string
val []string
lowKey *low.KeyReference[string]
lowVal *low.ValueReference[[]low.ValueReference[string]]
}
m := utils.CreateEmptyMapNode()
keys := make([]*req, len(s.Requirements))
i := 0
for k := range s.Requirements {
keys[i] = &req{key: k, val: s.Requirements[k]}
i++
}
i = 0
for k := range s.low.Requirements.Value {
if k.Value == keys[i].key {
gh := s.low.Requirements.Value[k]
keys[i].line = k.KeyNode.Line
keys[i].lowKey = &k
keys[i].lowVal = &gh
}
i++
}
sort.Slice(keys, func(i, j int) bool {
return keys[i].line < keys[j].line
})
for k := range keys {
l := utils.CreateStringNode(keys[k].key)
l.Line = keys[k].line
// for each key, extract all the values and order them.
type req struct {
line int
val string
}
reqs := make([]*req, len(keys[k].val))
for t := range keys[k].val {
reqs[t] = &req{val: keys[k].val[t], line: 9999 + t}
for _ = range keys[k].lowVal.Value[t].Value {
fh := keys[k].val[t]
df := keys[k].lowVal.Value[t].Value
if fh == df {
reqs[t].line = keys[k].lowVal.Value[t].ValueNode.Line
break
}
}
}
sort.Slice(reqs, func(i, j int) bool {
return reqs[i].line < reqs[j].line
})
sn := utils.CreateEmptySequenceNode()
for z := range reqs {
sn.Content = append(sn.Content, utils.CreateStringNode(reqs[z].val))
}
m.Content = append(m.Content, l, sn)
}
return m, nil
}

View File

@@ -16,10 +16,11 @@ import (
// NodeEntry represents a single node used by NodeBuilder.
type NodeEntry struct {
Tag string
Key string
Value any
Line int
Tag string
Key string
Value any
Line int
RenderZero bool
}
// NodeBuilder is a structure used by libopenapi high-level objects, to render themselves back to YAML.
@@ -30,13 +31,16 @@ type NodeBuilder struct {
Low any
}
const renderZero = "renderZero"
// NewNodeBuilder will create a new NodeBuilder instance, this is the only way to create a NodeBuilder.
// The function accepts a high level object and a low level object (need to be siblings/same type).
//
// Using reflection, a map of every field in the high level object is created, ready to be rendered.
func NewNodeBuilder(high any, low any) *NodeBuilder {
// create a new node builder
nb := &NodeBuilder{High: high}
nb := new(NodeBuilder)
nb.High = high
if low != nil {
nb.Low = low
}
@@ -103,21 +107,27 @@ func (n *NodeBuilder) add(key string, i int) {
field, _ := reflect.TypeOf(n.High).Elem().FieldByName(key)
tag := string(field.Tag.Get("yaml"))
tagName := strings.Split(tag, ",")[0]
if tag == "-" {
return
}
renderZeroVal := strings.Split(tag, ",")[1]
// extract the value of the field
fieldValue := reflect.ValueOf(n.High).Elem().FieldByName(key)
f := fieldValue.Interface()
value := reflect.ValueOf(f)
if f == nil || value.IsZero() {
if renderZeroVal != renderZero && (f == nil || value.IsZero()) {
return
}
// create a new node entry
nodeEntry := &NodeEntry{Tag: tagName, Key: key}
if renderZeroVal == renderZero {
nodeEntry.RenderZero = true
}
switch value.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
@@ -134,7 +144,7 @@ func (n *NodeBuilder) add(key string, i int) {
nodeEntry.Value = f
}
} else {
if !value.IsNil() && !value.IsZero() {
if (renderZeroVal == renderZero) || (!value.IsNil() && !value.IsZero()) {
nodeEntry.Value = f
}
}
@@ -158,13 +168,30 @@ func (n *NodeBuilder) add(key string, i int) {
fLow := lowFieldValue.Interface()
value = reflect.ValueOf(fLow)
switch value.Kind() {
case reflect.Map:
for _, ky := range value.MapKeys() {
if we, wok := ky.Interface().(low.HasKeyNode); wok {
nodeEntry.Line = we.GetKeyNode().Line
break
case reflect.Slice:
l := value.Len()
lines := make([]int, l)
for g := 0; g < l; g++ {
qw := value.Index(g).Interface()
if we, wok := qw.(low.HasKeyNode); wok {
lines[g] = we.GetKeyNode().Line
}
}
sort.Ints(lines)
nodeEntry.Line = lines[0] // pick the lowest line number so this key is sorted in order.
break
case reflect.Map:
l := value.Len()
lines := make([]int, l)
for q, ky := range value.MapKeys() {
if we, wok := ky.Interface().(low.HasKeyNode); wok {
lines[q] = we.GetKeyNode().Line
}
}
sort.Ints(lines)
nodeEntry.Line = lines[0] // pick the lowest line number, sort in order
case reflect.Struct:
y := value.Interface()
@@ -202,6 +229,10 @@ func (n *NodeBuilder) renderReference() []*yaml.Node {
// Render will render the NodeBuilder back to a YAML node, iterating over every NodeEntry defined
func (n *NodeBuilder) Render() *yaml.Node {
if len(n.Nodes) == 0 {
return utils.CreateEmptyMapNode()
}
// order nodes by line number, retain original order
m := utils.CreateEmptyMapNode()
if fg, ok := n.Low.(low.IsReferenced); ok {
@@ -223,7 +254,7 @@ func (n *NodeBuilder) Render() *yaml.Node {
for i := range n.Nodes {
node := n.Nodes[i]
n.AddYAMLNode(m, node.Tag, node.Key, node.Value, node.Line)
n.AddYAMLNode(m, node)
}
if len(m.Content) > 0 {
return m
@@ -234,35 +265,45 @@ func (n *NodeBuilder) Render() *yaml.Node {
// AddYAMLNode will add a new *yaml.Node to the parent node, using the tag, key and value provided.
// If the value is nil, then the node will not be added. This method is recursive, so it will dig down
// into any non-scalar types.
func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any, line int) *yaml.Node {
if value == nil {
func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *NodeEntry) *yaml.Node {
if entry.Value == nil {
return parent
}
// check the type
t := reflect.TypeOf(value)
t := reflect.TypeOf(entry.Value)
var l *yaml.Node
if tag != "" {
l = utils.CreateStringNode(tag)
if entry.Tag != "" {
l = utils.CreateStringNode(entry.Tag)
}
value := entry.Value
line := entry.Line
key := entry.Key
var valueNode *yaml.Node
switch t.Kind() {
case reflect.String:
val := value.(string)
if val == "" {
if val == "" && !entry.RenderZero {
return parent
}
valueNode = utils.CreateStringNode(val)
valueNode.Line = line
break
case reflect.Bool:
val := value.(bool)
if !val {
if !val && !entry.RenderZero {
return parent
}
valueNode = utils.CreateBoolNode("true")
if !val {
valueNode = utils.CreateBoolNode("false")
} else {
valueNode = utils.CreateBoolNode("true")
}
valueNode.Line = line
break
@@ -371,7 +412,7 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any,
// build out each map node in original order.
for _, cv := range orderedCollection {
n.AddYAMLNode(p, cv.Tag, cv.Key, cv.Value, cv.Line)
n.AddYAMLNode(p, cv)
}
if len(p.Content) > 0 {
valueNode = p
@@ -387,6 +428,7 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any,
var rawNode yaml.Node
m := reflect.ValueOf(value)
sl := utils.CreateEmptySequenceNode()
skip := false
for i := 0; i < m.Len(); i++ {
sqi := m.Index(i).Interface()
@@ -407,10 +449,29 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any,
nodes[1] = utils.CreateStringNode(glu.GoLowUntyped().(low.IsReferenced).GetReference())
rt.Content = append(rt.Content, nodes...)
sl.Content = append(sl.Content, rt)
skip = true
} else {
// TODO: pick up here in the AM looks like we need to correctly handle
if er, ko := sqi.(Renderable); ko {
rend, _ := er.(Renderable).MarshalYAML()
sl.Content = append(sl.Content, rend.(*yaml.Node))
skip = true
}
//}
}
}
}
} else {
if er, ko := sqi.(Renderable); ko {
rend, _ := er.(Renderable).MarshalYAML()
sl.Content = append(sl.Content, rend.(*yaml.Node))
skip = true
}
}
}
@@ -419,6 +480,9 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any,
valueNode = sl
break
}
if skip {
break
}
err := rawNode.Encode(value)
if err != nil {
@@ -468,6 +532,11 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any,
if *b {
valueNode = utils.CreateBoolNode("true")
valueNode.Line = line
} else {
if entry.RenderZero {
valueNode = utils.CreateBoolNode("false")
valueNode.Line = line
}
}
}
if b, bok := value.(*int64); bok {

View File

@@ -14,7 +14,7 @@ import (
)
type key struct {
Name string `yaml:"name"`
Name string `yaml:"name,omitempty"`
ref bool
refStr string
ln int
@@ -71,27 +71,27 @@ func (k key) MarshalYAML() (interface{}, error) {
}
type test1 struct {
Thing string `yaml:"thing"`
Thong int `yaml:"thong"`
Thrum int64 `yaml:"thrum"`
Thang float32 `yaml:"thang"`
Thung float64 `yaml:"thung"`
Thyme bool `yaml:"thyme"`
Thurm any `yaml:"thurm"`
Thugg *bool `yaml:"thugg"`
Thurr *int64 `yaml:"thurr"`
Thral *float64 `yaml:"thral"`
Tharg []string `yaml:"tharg"`
Type []string `yaml:"type"`
Throg []*key `yaml:"throg"`
Thrug map[string]string `yaml:"thrug"`
Thoom []map[string]string `yaml:"thoom"`
Thomp map[key]string `yaml:"thomp"`
Thump key `yaml:"thump"`
Thane key `yaml:"thane"`
Thunk key `yaml:"thunk"`
Thrim *key `yaml:"thrim"`
Thril map[string]*key `yaml:"thril"`
Thing string `yaml:"thing,omitempty"`
Thong int `yaml:"thong,omitempty"`
Thrum int64 `yaml:"thrum,omitempty"`
Thang float32 `yaml:"thang,omitempty"`
Thung float64 `yaml:"thung,omitempty"`
Thyme bool `yaml:"thyme,omitempty"`
Thurm any `yaml:"thurm,omitempty"`
Thugg *bool `yaml:"thugg,omitempty"`
Thurr *int64 `yaml:"thurr,omitempty"`
Thral *float64 `yaml:"thral,omitempty"`
Tharg []string `yaml:"tharg,omitempty"`
Type []string `yaml:"type,omitempty"`
Throg []*key `yaml:"throg,omitempty"`
Thrug map[string]string `yaml:"thrug,omitempty"`
Thoom []map[string]string `yaml:"thoom,omitempty"`
Thomp map[key]string `yaml:"thomp,omitempty"`
Thump key `yaml:"thump,omitempty"`
Thane key `yaml:"thane,omitempty"`
Thunk key `yaml:"thunk,omitempty"`
Thrim *key `yaml:"thrim,omitempty"`
Thril map[string]*key `yaml:"thril,omitempty"`
Extensions map[string]any `yaml:"-"`
ignoreMe string `yaml:"-"`
IgnoreMe string `yaml:"-"`
@@ -159,7 +159,7 @@ func TestNewNodeBuilder(t *testing.T) {
ignoreMe: "I should never be seen!",
Thing: "ding",
Thong: 1,
Thurm: &test1{},
Thurm: nil,
Thrum: 1234567,
Thang: 2.2,
Thung: 3.33333,
@@ -195,16 +195,12 @@ func TestNewNodeBuilder(t *testing.T) {
},
}
nb := NewNodeBuilder(&t1, &t1)
nb := NewNodeBuilder(&t1, nil)
node := nb.Render()
data, _ := yaml.Marshal(node)
desired := `thrug:
chicken: nuggets
thomp:
meddy: princess
thing: ding
desired := `thing: ding
thong: "1"
thrum: "1234567"
thang: 2.20
@@ -217,9 +213,13 @@ tharg:
- chicken
- nuggets
type: chicken
thrug:
chicken: nuggets
thoom:
- maddy: champion
- ember: naughty
thomp:
meddy: princess
x-pizza: time`
assert.Equal(t, desired, strings.TrimSpace(string(data)))
@@ -306,22 +306,25 @@ func TestNewNodeBuilder_NoValue(t *testing.T) {
Thing: "",
}
nodeEnty := NodeEntry{}
nb := NewNodeBuilder(&t1, &t1)
node := nb.AddYAMLNode(nil, "", "", nil, 0)
node := nb.AddYAMLNode(nil, &nodeEnty)
assert.Nil(t, node)
}
func TestNewNodeBuilder_EmptyString(t *testing.T) {
t1 := new(test1)
nodeEnty := NodeEntry{}
nb := NewNodeBuilder(t1, t1)
node := nb.AddYAMLNode(nil, "", "", "", 0)
node := nb.AddYAMLNode(nil, &nodeEnty)
assert.Nil(t, node)
}
func TestNewNodeBuilder_Bool(t *testing.T) {
t1 := new(test1)
nb := NewNodeBuilder(t1, t1)
node := nb.AddYAMLNode(nil, "", "", false, 0)
nodeEnty := NodeEntry{}
node := nb.AddYAMLNode(nil, &nodeEnty)
assert.Nil(t, node)
}
@@ -329,7 +332,8 @@ func TestNewNodeBuilder_Int(t *testing.T) {
t1 := new(test1)
nb := NewNodeBuilder(t1, t1)
p := utils.CreateEmptyMapNode()
node := nb.AddYAMLNode(p, "p", "p", 12, 0)
nodeEnty := NodeEntry{Tag: "p", Value: 12, Key: "p"}
node := nb.AddYAMLNode(p, &nodeEnty)
assert.NotNil(t, node)
assert.Len(t, node.Content, 2)
assert.Equal(t, "12", node.Content[1].Value)
@@ -339,7 +343,8 @@ func TestNewNodeBuilder_Int64(t *testing.T) {
t1 := new(test1)
nb := NewNodeBuilder(t1, t1)
p := utils.CreateEmptyMapNode()
node := nb.AddYAMLNode(p, "p", "p", int64(234556), 0)
nodeEnty := NodeEntry{Tag: "p", Value: int64(234556), Key: "p"}
node := nb.AddYAMLNode(p, &nodeEnty)
assert.NotNil(t, node)
assert.Len(t, node.Content, 2)
assert.Equal(t, "234556", node.Content[1].Value)
@@ -349,7 +354,8 @@ func TestNewNodeBuilder_Float32(t *testing.T) {
t1 := new(test1)
nb := NewNodeBuilder(t1, t1)
p := utils.CreateEmptyMapNode()
node := nb.AddYAMLNode(p, "p", "p", float32(1234.23), 0)
nodeEnty := NodeEntry{Tag: "p", Value: float32(1234.23), Key: "p"}
node := nb.AddYAMLNode(p, &nodeEnty)
assert.NotNil(t, node)
assert.Len(t, node.Content, 2)
assert.Equal(t, "1234.23", node.Content[1].Value)
@@ -359,7 +365,8 @@ func TestNewNodeBuilder_Float64(t *testing.T) {
t1 := new(test1)
nb := NewNodeBuilder(t1, t1)
p := utils.CreateEmptyMapNode()
node := nb.AddYAMLNode(p, "p", "p", 1234.232323, 0)
nodeEnty := NodeEntry{Tag: "p", Value: 1234.232323, Key: "p"}
node := nb.AddYAMLNode(p, &nodeEnty)
assert.NotNil(t, node)
assert.Len(t, node.Content, 2)
assert.Equal(t, "1234.232323", node.Content[1].Value)
@@ -478,7 +485,8 @@ func TestNewNodeBuilder_MissingLabel(t *testing.T) {
t1 := new(test1)
nb := NewNodeBuilder(t1, t1)
p := utils.CreateEmptyMapNode()
node := nb.AddYAMLNode(p, "", "p", 1234.232323, 0)
nodeEnty := NodeEntry{Value: 1234.232323, Key: "p"}
node := nb.AddYAMLNode(p, &nodeEnty)
assert.NotNil(t, node)
assert.Len(t, node.Content, 0)
}

View File

@@ -50,6 +50,7 @@ type Document struct {
// an empty security requirement ({}) can be included in the array.
// - https://spec.openapis.org/oas/v3.1.0#security-requirement-object
Security []*base.SecurityRequirement `json:"security,omitempty" yaml:"security,omitempty"`
//Security []*base.SecurityRequirement `json:"-" yaml:"-"`
// Tags is a slice of base.Tag instances defined by the specification
// A list of tags used by the document with additional metadata. The order of the tags can be used to reflect on
@@ -70,7 +71,7 @@ type Document struct {
// The default value for the $schema keyword within Schema Objects contained within this OAS document.
// This MUST be in the form of a URI.
// - https://spec.openapis.org/oas/v3.1.0#schema-object
JsonSchemaDialect string `json:"$schema,omitempty" yaml:"$schema,omitempty"`
JsonSchemaDialect string `json:"jsonSchemaDialect,omitempty" yaml:"jsonSchemaDialect,omitempty"`
// Webhooks is a 3.1+ property that is similar to callbacks, except, this defines incoming webhooks.
// The incoming webhooks that MAY be received as part of this API and that the API consumer MAY choose to implement.

View File

@@ -14,7 +14,7 @@ import (
type RequestBody struct {
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Content map[string]*MediaType `json:"content,omitempty" yaml:"content,omitempty"`
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
Required *bool `json:"required,omitempty" yaml:"required,renderZero,omitempty"`
Extensions map[string]any `json:"-" yaml:"-"`
low *low.RequestBody
}
@@ -24,7 +24,9 @@ func NewRequestBody(rb *low.RequestBody) *RequestBody {
r := new(RequestBody)
r.low = rb
r.Description = rb.Description.Value
r.Required = rb.Required.Value
if rb.Required.ValueNode != nil {
r.Required = &rb.Required.Value
}
r.Extensions = high.ExtractExtensions(rb.Extensions)
r.Content = ExtractContent(rb.Content.Value)
return r

View File

@@ -11,9 +11,10 @@ import (
func TestRequestBody_MarshalYAML(t *testing.T) {
rb := true
req := &RequestBody{
Description: "beer",
Required: true,
Required: &rb,
Extensions: map[string]interface{}{"x-high-gravity": "why not?"},
}
@@ -26,3 +27,38 @@ x-high-gravity: why not?`
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
}
func TestRequestBody_MarshalNoRequired(t *testing.T) {
rb := false
req := &RequestBody{
Description: "beer",
Required: &rb,
Extensions: map[string]interface{}{"x-high-gravity": "why not?"},
}
rend, _ := req.Render()
desired := `description: beer
required: false
x-high-gravity: why not?`
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
}
func TestRequestBody_MarshalRequiredNil(t *testing.T) {
req := &RequestBody{
Description: "beer",
Extensions: map[string]interface{}{"x-high-gravity": "why not?"},
}
rend, _ := req.Render()
desired := `description: beer
x-high-gravity: why not?`
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
}

View File

@@ -1468,6 +1468,31 @@ func TestSchema_Hash_AdditionalPropsSlice(t *testing.T) {
assert.Equal(t, lHash, rHash)
}
func TestSchema_Hash_AdditionalPropsSliceNoMap(t *testing.T) {
left := `schema:
additionalProperties:
- hello`
right := `schema:
additionalProperties:
- hello`
var lNode, rNode yaml.Node
_ = yaml.Unmarshal([]byte(left), &lNode)
_ = yaml.Unmarshal([]byte(right), &rNode)
lDoc, _ := ExtractSchema(lNode.Content[0], nil)
rDoc, _ := ExtractSchema(rNode.Content[0], nil)
assert.NotNil(t, lDoc)
assert.NotNil(t, rDoc)
lHash := lDoc.Value.Schema().Hash()
rHash := rDoc.Value.Schema().Hash()
assert.Equal(t, lHash, rHash)
}
func TestSchema_Hash_NotEqual(t *testing.T) {
left := `schema:
title: an OK message - but different

View File

@@ -1536,3 +1536,27 @@ func TestGenerateHashString(t *testing.T) {
GenerateHashString("hello"))
}
func TestSetReference(t *testing.T) {
type testObj struct {
*Reference
}
n := testObj{Reference: &Reference{}}
SetReference(&n, "#/pigeon/street")
assert.Equal(t, "#/pigeon/street", n.GetReference())
}
func TestSetReference_nil(t *testing.T) {
type testObj struct {
*Reference
}
n := testObj{Reference: &Reference{}}
SetReference(nil, "#/pigeon/street")
assert.NotEqual(t, "#/pigeon/street", n.GetReference())
}

View File

@@ -27,6 +27,7 @@ type hotdog struct {
LotsOfUnknowns []NodeReference[any]
Where map[string]NodeReference[any]
There map[string]NodeReference[string]
AllTheThings NodeReference[map[KeyReference[string]]ValueReference[string]]
}
func TestBuildModel_Mismatch(t *testing.T) {
@@ -99,7 +100,10 @@ where:
bears: 200
there:
oh: yeah
care: bear`
care: bear
allTheThings:
beer: isGood
cake: isNice`
var rootNode yaml.Node
mErr := yaml.Unmarshal([]byte(yml), &rootNode)
@@ -129,6 +133,16 @@ there:
assert.Len(t, hd.There, 2)
assert.Equal(t, "bear", hd.There["care"].Value)
assert.Equal(t, 324938249028.98234892374892374923874823974, hd.Mustard.Value)
allTheThings := hd.AllTheThings.Value
for i := range allTheThings {
if i.Value == "beer" {
assert.Equal(t, "isGood", allTheThings[i].Value)
}
if i.Value == "cake" {
assert.Equal(t, "isNice", allTheThings[i].Value)
}
}
assert.NoError(t, cErr)
}

View File

@@ -269,7 +269,9 @@ func (n ValueReference[T]) MarshalYAML() (interface{}, error) {
nodes := make([]*yaml.Node, 2)
nodes[0] = utils.CreateStringNode("$ref")
nodes[1] = utils.CreateStringNode(n.Reference)
return nodes, nil
m := utils.CreateEmptyMapNode()
m.Content = nodes
return m, nil
}
var h yaml.Node
e := n.ValueNode.Decode(&h)

View File

@@ -5,6 +5,9 @@ package low
import (
"crypto/sha256"
"fmt"
"github.com/pb33f/libopenapi/utils"
"strings"
"testing"
"github.com/pb33f/libopenapi/index"
@@ -558,3 +561,196 @@ func TestHashToString(t *testing.T) {
HashToString(sha256.Sum256([]byte("12345"))))
}
func TestReference_IsReference(t *testing.T) {
ref := Reference{
Reference: "#/components/schemas/SomeSchema",
}
assert.True(t, ref.IsReference())
}
func TestNodeReference_NodeLineNumber(t *testing.T) {
n := utils.CreateStringNode("pizza")
nr := NodeReference[string]{
Value: "pizza",
ValueNode: n,
}
n.Line = 3
assert.Equal(t, 3, nr.NodeLineNumber())
}
func TestNodeReference_NodeLineNumberEmpty(t *testing.T) {
nr := NodeReference[string]{
Value: "pizza",
}
assert.Equal(t, 0, nr.NodeLineNumber())
}
func TestNodeReference_GetReference(t *testing.T) {
nr := NodeReference[string]{
Reference: "#/happy/sunday",
}
assert.Equal(t, "#/happy/sunday", nr.GetReference())
}
func TestNodeReference_SetReference(t *testing.T) {
nr := NodeReference[string]{}
nr.SetReference("#/happy/sunday")
}
func TestNodeReference_IsReference(t *testing.T) {
nr := NodeReference[string]{
ReferenceNode: true,
}
assert.True(t, nr.IsReference())
}
func TestNodeReference_GetKeyNode(t *testing.T) {
nr := NodeReference[string]{
KeyNode: utils.CreateStringNode("pizza"),
}
assert.Equal(t, "pizza", nr.GetKeyNode().Value)
}
func TestNodeReference_GetValueUntyped(t *testing.T) {
type anything struct {
thing string
}
nr := NodeReference[any]{
Value: anything{thing: "ding"},
}
assert.Equal(t, "{ding}", fmt.Sprint(nr.GetValueUntyped()))
}
func TestValueReference_NodeLineNumber(t *testing.T) {
n := utils.CreateStringNode("pizza")
nr := ValueReference[string]{
Value: "pizza",
ValueNode: n,
}
n.Line = 3
assert.Equal(t, 3, nr.NodeLineNumber())
}
func TestValueReference_NodeLineNumber_Nil(t *testing.T) {
nr := ValueReference[string]{
Value: "pizza",
}
assert.Equal(t, 0, nr.NodeLineNumber())
}
func TestValueReference_GetReference(t *testing.T) {
nr := ValueReference[string]{
Reference: "#/happy/sunday",
}
assert.Equal(t, "#/happy/sunday", nr.GetReference())
}
func TestValueReference_SetReference(t *testing.T) {
nr := ValueReference[string]{}
nr.SetReference("#/happy/sunday")
}
func TestValueReference_GetValueUntyped(t *testing.T) {
type anything struct {
thing string
}
nr := ValueReference[any]{
Value: anything{thing: "ding"},
}
assert.Equal(t, "{ding}", fmt.Sprint(nr.GetValueUntyped()))
}
func TestValueReference_IsReference(t *testing.T) {
nr := NodeReference[string]{
ReferenceNode: true,
}
assert.True(t, nr.IsReference())
}
func TestValueReference_MarshalYAML_Ref(t *testing.T) {
nr := ValueReference[string]{
ReferenceNode: true,
Reference: "#/burgers/beer",
}
data, _ := yaml.Marshal(nr)
assert.Equal(t, `$ref: '#/burgers/beer'`, strings.TrimSpace(string(data)))
}
func TestValueReference_MarshalYAML(t *testing.T) {
v := map[string]interface{}{
"beer": "burger",
"wine": "cheese",
}
var enc yaml.Node
enc.Encode(&v)
nr := ValueReference[any]{
Value: v,
ValueNode: &enc,
}
data, _ := yaml.Marshal(nr)
expected := `beer: burger
wine: cheese`
assert.Equal(t, expected, strings.TrimSpace(string(data)))
}
func TestKeyReference_GetValueUntyped(t *testing.T) {
type anything struct {
thing string
}
nr := KeyReference[any]{
Value: anything{thing: "ding"},
}
assert.Equal(t, "{ding}", fmt.Sprint(nr.GetValueUntyped()))
}
func TestKeyReference_GetKeyNode(t *testing.T) {
kn := utils.CreateStringNode("pizza")
kn.Line = 3
nr := KeyReference[any]{
KeyNode: kn,
}
assert.Equal(t, 3, nr.GetKeyNode().Line)
assert.Equal(t, "pizza", nr.GetKeyNode().Value)
}

View File

@@ -20,7 +20,10 @@ func initTest() {
data, _ := ioutil.ReadFile("../../../test_specs/petstorev2-complete.yaml")
info, _ := datamodel.ExtractSpecInfo(data)
var err []error
doc, err = CreateDocument(info)
doc, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
wait := true
for wait {
select {
@@ -38,7 +41,10 @@ func BenchmarkCreateDocument(b *testing.B) {
data, _ := ioutil.ReadFile("../../../test_specs/petstorev2-complete.yaml")
info, _ := datamodel.ExtractSpecInfo(data)
for i := 0; i < b.N; i++ {
doc, _ = CreateDocument(info)
doc, _ = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
}
}

View File

@@ -11,28 +11,29 @@ const (
HeadersLabel = "headers"
ExpressionLabel = "expression"
InfoLabel = "info"
SwaggerLabel = "swagger"
ParametersLabel = "parameters"
RequestBodyLabel = "requestBody"
RequestBodiesLabel = "requestBodies"
ResponsesLabel = "responses"
CallbacksLabel = "callbacks"
ContentLabel = "content"
PathsLabel = "paths"
PathLabel = "path"
WebhooksLabel = "webhooks"
JSONSchemaDialectLabel = "jsonSchemaDialect"
GetLabel = "get"
PostLabel = "post"
PatchLabel = "patch"
PutLabel = "put"
DeleteLabel = "delete"
OptionsLabel = "options"
HeadLabel = "head"
TraceLabel = "trace"
LinksLabel = "links"
DefaultLabel = "default"
SecurityLabel = "security"
SwaggerLabel = "swagger"
ParametersLabel = "parameters"
RequestBodyLabel = "requestBody"
RequestBodiesLabel = "requestBodies"
ResponsesLabel = "responses"
CallbacksLabel = "callbacks"
ContentLabel = "content"
PathsLabel = "paths"
PathLabel = "path"
WebhooksLabel = "webhooks"
JSONSchemaDialectLabel = "jsonSchemaDialect"
JSONSchemaLabel = "$schema"
GetLabel = "get"
PostLabel = "post"
PatchLabel = "patch"
PutLabel = "put"
DeleteLabel = "delete"
OptionsLabel = "options"
HeadLabel = "head"
TraceLabel = "trace"
LinksLabel = "links"
DefaultLabel = "default"
SecurityLabel = "security"
SecuritySchemesLabel = "securitySchemes"
OAuthFlowsLabel = "flows"
VariablesLabel = "variables"

View File

@@ -19,6 +19,7 @@ func initTest() {
data, _ := ioutil.ReadFile("../../../test_specs/burgershop.openapi.yaml")
info, _ := datamodel.ExtractSpecInfo(data)
var err []error
// deprecated function test.
doc, err = CreateDocument(info)
if err != nil {
panic("broken something")
@@ -29,7 +30,10 @@ func BenchmarkCreateDocument(b *testing.B) {
data, _ := ioutil.ReadFile("../../../test_specs/burgershop.openapi.yaml")
info, _ := datamodel.ExtractSpecInfo(data)
for i := 0; i < b.N; i++ {
doc, _ = CreateDocument(info)
doc, _ = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
}
}
@@ -37,7 +41,10 @@ func BenchmarkCreateDocument_Circular(b *testing.B) {
data, _ := ioutil.ReadFile("../../../test_specs/circular-tests.yaml")
info, _ := datamodel.ExtractSpecInfo(data)
for i := 0; i < b.N; i++ {
_, err := CreateDocument(info)
_, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
if err != nil {
panic("this should not error")
}
@@ -51,7 +58,10 @@ func BenchmarkCreateDocument_k8s(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := CreateDocument(info)
_, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
if err != nil {
panic("this should not error")
}
@@ -62,7 +72,10 @@ func TestCircularReferenceError(t *testing.T) {
data, _ := ioutil.ReadFile("../../../test_specs/circular-tests.yaml")
info, _ := datamodel.ExtractSpecInfo(data)
circDoc, err := CreateDocument(info)
circDoc, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
assert.NotNil(t, circDoc)
assert.Len(t, err, 3)
}
@@ -72,7 +85,10 @@ func BenchmarkCreateDocument_Stripe(b *testing.B) {
info, _ := datamodel.ExtractSpecInfo(data)
for i := 0; i < b.N; i++ {
_, err := CreateDocument(info)
_, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
if err != nil {
panic("this should not error")
}
@@ -83,7 +99,10 @@ func BenchmarkCreateDocument_Petstore(b *testing.B) {
data, _ := ioutil.ReadFile("../../../test_specs/petstorev3.json")
info, _ := datamodel.ExtractSpecInfo(data)
for i := 0; i < b.N; i++ {
_, err := CreateDocument(info)
_, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
if err != nil {
panic("this should not error")
}
@@ -94,7 +113,11 @@ func TestCreateDocumentStripe(t *testing.T) {
data, _ := ioutil.ReadFile("../../../test_specs/stripe.yaml")
info, _ := datamodel.ExtractSpecInfo(data)
d, err := CreateDocument(info)
d, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
BasePath: "/here",
})
assert.Len(t, err, 3)
assert.Equal(t, "3.0.0", d.Version.Value)
@@ -137,7 +160,10 @@ func TestCreateDocument_WebHooks_Error(t *testing.T) {
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
var err []error
_, err = CreateDocument(info)
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
assert.Len(t, err, 1)
}
@@ -523,7 +549,10 @@ components:
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
var err []error
doc, err = CreateDocument(info)
doc, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
assert.Len(t, err, 0)
ob := doc.Components.Value.FindSchema("bork").Value
@@ -539,7 +568,10 @@ webhooks:
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
var err []error
doc, err = CreateDocument(info)
doc, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
assert.Len(t, err, 1)
}
@@ -552,7 +584,10 @@ components:
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
var err []error
_, err = CreateDocument(info)
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
assert.Len(t, err, 1)
}
@@ -565,7 +600,10 @@ paths:
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
var err []error
_, err = CreateDocument(info)
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
assert.Len(t, err, 1)
}
@@ -576,7 +614,10 @@ tags:
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
var err []error
_, err = CreateDocument(info)
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
assert.Len(t, err, 1)
}
@@ -587,7 +628,10 @@ security:
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
var err []error
_, err = CreateDocument(info)
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
assert.Len(t, err, 1)
}
@@ -598,7 +642,10 @@ externalDocs:
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
var err []error
_, err = CreateDocument(info)
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
assert.Len(t, err, 1)
}
@@ -612,7 +659,10 @@ func ExampleCreateDocument() {
info, _ := datamodel.ExtractSpecInfo(petstoreBytes)
// build low-level document model
document, errors := CreateDocument(info)
document, errors := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
})
// if something went wrong, a slice of errors is returned
if len(errors) > 0 {

View File

@@ -70,7 +70,7 @@ type Document interface {
// **IMPORTANT** This method only supports OpenAPI Documents. The Swagger model will not support mutations correctly
// and will not update when called. This choice has been made because we don't want to continue supporting Swagger,
// it's too old, so it should be motivation to upgrade to OpenAPI 3.
RenderAndReload() ([]byte, *Document, *DocumentModel[v3high.Document], []error)
RenderAndReload() ([]byte, Document, *DocumentModel[v3high.Document], []error)
// Serialize will re-render a Document back into a []byte slice. If any modifications have been made to the
// underlying data model using low level APIs, then those changes will be reflected in the serialized output.
@@ -156,7 +156,7 @@ func (d *document) Serialize() ([]byte, error) {
}
}
func (d *document) RenderAndReload() ([]byte, *Document, *DocumentModel[v3high.Document], []error) {
func (d *document) RenderAndReload() ([]byte, Document, *DocumentModel[v3high.Document], []error) {
if d.highSwaggerModel != nil && d.highOpenAPI3Model == nil {
return nil, nil, nil, []error{errors.New("this method only supports OpenAPI 3 documents, not Swagger")}
}
@@ -166,15 +166,15 @@ func (d *document) RenderAndReload() ([]byte, *Document, *DocumentModel[v3high.D
}
newDoc, err := NewDocument(newBytes)
if err != nil {
return newBytes, &newDoc, nil, []error{err}
return newBytes, newDoc, nil, []error{err}
}
// build the model.
model, errs := newDoc.BuildV3Model()
if errs != nil {
return newBytes, &newDoc, model, errs
return newBytes, newDoc, model, errs
}
// this document is now dead, long live the new document!
return newBytes, &newDoc, model, nil
return newBytes, newDoc, model, nil
}
func (d *document) BuildV2Model() (*DocumentModel[v2high.Swagger], []error) {
@@ -278,14 +278,13 @@ func CompareDocuments(original, updated Document) (*model.DocumentChanges, []err
}
v3ModelRight, errs := updated.BuildV3Model()
if len(errs) > 0 {
errors = errs
errors = append(errors, errs...)
}
if v3ModelLeft != nil && v3ModelRight != nil {
return what_changed.CompareOpenAPIDocuments(v3ModelLeft.Model.GoLow(), v3ModelRight.Model.GoLow()), errors
} else {
return nil, errs
return nil, errors
}
}
if original.GetSpecInfo().SpecType == utils.OpenApi2 && updated.GetSpecInfo().SpecType == utils.OpenApi2 {
v2ModelLeft, errs := original.BuildV2Model()
@@ -294,13 +293,13 @@ func CompareDocuments(original, updated Document) (*model.DocumentChanges, []err
}
v2ModelRight, errs := updated.BuildV2Model()
if len(errs) > 0 {
errors = errs
errors = append(errors, errs...)
}
if v2ModelLeft != nil && v2ModelRight != nil {
return what_changed.CompareSwaggerDocuments(v2ModelLeft.Model.GoLow(), v2ModelRight.Model.GoLow()), errors
} else {
return nil, errs
return nil, errors
}
}
return nil, nil
return nil, []error{fmt.Errorf("unable to compare documents, one or both documents are not of the same version")}
}

601
document_examples_test.go Normal file
View File

@@ -0,0 +1,601 @@
// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT
package libopenapi
import (
"fmt"
"github.com/pb33f/libopenapi/datamodel"
"io/ioutil"
"net/url"
"strings"
"testing"
"github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/base"
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/resolver"
"github.com/pb33f/libopenapi/utils"
"github.com/stretchr/testify/assert"
)
func ExampleNewDocument_fromOpenAPI3Document() {
// How to read in an OpenAPI 3 Specification, into a Document.
// load an OpenAPI 3 specification from bytes
petstore, _ := ioutil.ReadFile("test_specs/petstorev3.json")
// create a new document from specification bytes
document, err := NewDocument(petstore)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// because we know this is a v3 spec, we can build a ready to go model from it.
v3Model, errors := document.BuildV3Model()
// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
for i := range errors {
fmt.Printf("error: %e\n", errors[i])
}
panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
}
// get a count of the number of paths and schemas.
paths := len(v3Model.Model.Paths.PathItems)
schemas := len(v3Model.Model.Components.Schemas)
// print the number of paths and schemas in the document
fmt.Printf("There are %d paths and %d schemas in the document", paths, schemas)
// Output: There are 13 paths and 8 schemas in the document
}
func ExampleNewDocument_fromWithDocumentConfigurationFailure() {
// This example shows how to create a document that prevents the loading of external references/
// from files or the network
// load in the Digital Ocean OpenAPI specification
digitalOcean, _ := ioutil.ReadFile("test_specs/digitalocean.yaml")
// create a DocumentConfiguration that prevents loading file and remote references
config := datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
}
// create a new document from specification bytes
doc, err := NewDocumentWithConfiguration(digitalOcean, &config)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// only errors will be thrown, so just capture them and print the number of errors.
_, errors := doc.BuildV3Model()
// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
fmt.Println("Error building Digital Ocean spec errors reported")
}
// Output: Error building Digital Ocean spec errors reported
}
func ExampleNewDocument_fromWithDocumentConfigurationSuccess() {
// This example shows how to create a document that prevents the loading of external references/
// from files or the network
// load in the Digital Ocean OpenAPI specification
digitalOcean, _ := ioutil.ReadFile("test_specs/digitalocean.yaml")
// Digital Ocean needs a baseURL to be set, so we can resolve relative references.
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
// create a DocumentConfiguration that allows loading file and remote references, and sets the baseURL
// to somewhere that can resolve the relative references.
config := datamodel.DocumentConfiguration{
AllowFileReferences: true,
AllowRemoteReferences: true,
BaseURL: baseURL,
}
// create a new document from specification bytes
doc, err := NewDocumentWithConfiguration(digitalOcean, &config)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// only errors will be thrown, so just capture them and print the number of errors.
_, errors := doc.BuildV3Model()
// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
fmt.Println("Error building Digital Ocean spec errors reported")
} else {
fmt.Println("Digital Ocean spec built successfully")
}
// Output: Digital Ocean spec built successfully
}
func ExampleNewDocument_fromSwaggerDocument() {
// How to read in a Swagger / OpenAPI 2 Specification, into a Document.
// load a Swagger specification from bytes
petstore, _ := ioutil.ReadFile("test_specs/petstorev2.json")
// create a new document from specification bytes
document, err := NewDocument(petstore)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// because we know this is a v2 spec, we can build a ready to go model from it.
v2Model, errors := document.BuildV2Model()
// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
for i := range errors {
fmt.Printf("error: %e\n", errors[i])
}
panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
}
// get a count of the number of paths and schemas.
paths := len(v2Model.Model.Paths.PathItems)
schemas := len(v2Model.Model.Definitions.Definitions)
// print the number of paths and schemas in the document
fmt.Printf("There are %d paths and %d schemas in the document", paths, schemas)
// Output: There are 14 paths and 6 schemas in the document
}
func ExampleNewDocument_fromUnknownVersion() {
// load an unknown version of an OpenAPI spec
petstore, _ := ioutil.ReadFile("test_specs/burgershop.openapi.yaml")
// create a new document from specification bytes
document, err := NewDocument(petstore)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
var paths, schemas int
var errors []error
// We don't know which type of document this is, so we can use the spec info to inform us
if document.GetSpecInfo().SpecType == utils.OpenApi3 {
v3Model, errs := document.BuildV3Model()
if len(errs) > 0 {
errors = errs
}
if len(errors) <= 0 {
paths = len(v3Model.Model.Paths.PathItems)
schemas = len(v3Model.Model.Components.Schemas)
}
}
if document.GetSpecInfo().SpecType == utils.OpenApi2 {
v2Model, errs := document.BuildV2Model()
if len(errs) > 0 {
errors = errs
}
if len(errors) <= 0 {
paths = len(v2Model.Model.Paths.PathItems)
schemas = len(v2Model.Model.Definitions.Definitions)
}
}
// if anything went wrong when building the model, report errors.
if len(errors) > 0 {
for i := range errors {
fmt.Printf("error: %e\n", errors[i])
}
panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
}
// print the number of paths and schemas in the document
fmt.Printf("There are %d paths and %d schemas in the document", paths, schemas)
// Output: There are 5 paths and 6 schemas in the document
}
func ExampleNewDocument_mutateValuesAndSerialize() {
// How to mutate values in an OpenAPI Specification, without re-ordering original content.
// create very small, and useless spec that does nothing useful, except showcase this feature.
spec := `
openapi: 3.1.0
info:
title: This is a title
contact:
name: Some Person
email: some@emailaddress.com
license:
url: http://some-place-on-the-internet.com/license
`
// create a new document from specification bytes
document, err := NewDocument([]byte(spec))
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// because we know this is a v3 spec, we can build a ready to go model from it.
v3Model, errors := document.BuildV3Model()
// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
for i := range errors {
fmt.Printf("error: %e\n", errors[i])
}
panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
}
// mutate the title, to do this we currently need to drop down to the low-level API.
v3Model.Model.GoLow().Info.Value.Title.Mutate("A new title for a useless spec")
// mutate the email address in the contact object.
v3Model.Model.GoLow().Info.Value.Contact.Value.Email.Mutate("buckaroo@pb33f.io")
// mutate the name in the contact object.
v3Model.Model.GoLow().Info.Value.Contact.Value.Name.Mutate("Buckaroo")
// mutate the URL for the license object.
v3Model.Model.GoLow().Info.Value.License.Value.URL.Mutate("https://pb33f.io/license")
// serialize the document back into the original YAML or JSON
mutatedSpec, serialError := document.Serialize()
// if something went wrong serializing
if serialError != nil {
panic(fmt.Sprintf("cannot serialize document: %e", serialError))
}
// print our modified spec!
fmt.Println(string(mutatedSpec))
// Output: openapi: 3.1.0
//info:
// title: A new title for a useless spec
// contact:
// name: Buckaroo
// email: buckaroo@pb33f.io
// license:
// url: https://pb33f.io/license
}
func ExampleCompareDocuments_openAPI() {
// How to compare two different OpenAPI specifications.
// load an original OpenAPI 3 specification from bytes
burgerShopOriginal, _ := ioutil.ReadFile("test_specs/burgershop.openapi.yaml")
// load an **updated** OpenAPI 3 specification from bytes
burgerShopUpdated, _ := ioutil.ReadFile("test_specs/burgershop.openapi-modified.yaml")
// create a new document from original specification bytes
originalDoc, err := NewDocument(burgerShopOriginal)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// create a new document from updated specification bytes
updatedDoc, err := NewDocument(burgerShopUpdated)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// Compare documents for all changes made
documentChanges, errs := CompareDocuments(originalDoc, updatedDoc)
// If anything went wrong when building models for documents.
if len(errs) > 0 {
for i := range errs {
fmt.Printf("error: %e\n", errs[i])
}
panic(fmt.Sprintf("cannot compare documents: %d errors reported", len(errs)))
}
// Extract SchemaChanges from components changes.
schemaChanges := documentChanges.ComponentsChanges.SchemaChanges
// Print out some interesting stats about the OpenAPI document changes.
fmt.Printf("There are %d changes, of which %d are breaking. %v schemas have changes.",
documentChanges.TotalChanges(), documentChanges.TotalBreakingChanges(), len(schemaChanges))
//Output: There are 72 changes, of which 17 are breaking. 5 schemas have changes.
}
func ExampleCompareDocuments_swagger() {
// How to compare two different Swagger specifications.
// load an original OpenAPI 3 specification from bytes
petstoreOriginal, _ := ioutil.ReadFile("test_specs/petstorev2-complete.yaml")
// load an **updated** OpenAPI 3 specification from bytes
petstoreUpdated, _ := ioutil.ReadFile("test_specs/petstorev2-complete-modified.yaml")
// create a new document from original specification bytes
originalDoc, err := NewDocument(petstoreOriginal)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// create a new document from updated specification bytes
updatedDoc, err := NewDocument(petstoreUpdated)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// Compare documents for all changes made
documentChanges, errs := CompareDocuments(originalDoc, updatedDoc)
// If anything went wrong when building models for documents.
if len(errs) > 0 {
for i := range errs {
fmt.Printf("error: %e\n", errs[i])
}
panic(fmt.Sprintf("cannot compare documents: %d errors reported", len(errs)))
}
// Extract SchemaChanges from components changes.
schemaChanges := documentChanges.ComponentsChanges.SchemaChanges
// Print out some interesting stats about the Swagger document changes.
fmt.Printf("There are %d changes, of which %d are breaking. %v schemas have changes.",
documentChanges.TotalChanges(), documentChanges.TotalBreakingChanges(), len(schemaChanges))
//Output: There are 52 changes, of which 27 are breaking. 5 schemas have changes.
}
func TestDocument_Paths_As_Array(t *testing.T) {
// paths can now be wrapped in an array.
spec := `{
"openapi": "3.1.0",
"paths": [
"/": {
"get": {}
}
]
}
`
// create a new document from specification bytes
doc, err := NewDocument([]byte(spec))
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
v3Model, _ := doc.BuildV3Model()
assert.NotNil(t, v3Model)
}
// If you want to know more about circular references that have been found
// during the parsing/indexing/building of a document, you can capture the
// []errors thrown which are pointers to *resolver.ResolvingError
func ExampleNewDocument_infinite_circular_references() {
// create a specification with an obvious and deliberate circular reference
spec := `openapi: "3.1"
components:
schemas:
One:
description: "test one"
properties:
things:
"$ref": "#/components/schemas/Two"
required:
- things
Two:
description: "test two"
properties:
testThing:
"$ref": "#/components/schemas/One"
required:
- testThing
`
// create a new document from specification bytes
doc, err := NewDocument([]byte(spec))
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
_, errs := doc.BuildV3Model()
// extract resolving error
resolvingError := errs[0]
// resolving error is a pointer to *resolver.ResolvingError
// which provides access to rich details about the error.
circularReference := resolvingError.(*resolver.ResolvingError).CircularReference
// capture the journey with all details
var buf strings.Builder
for n := range circularReference.Journey {
// add the full definition name to the journey.
buf.WriteString(circularReference.Journey[n].Definition)
if n < len(circularReference.Journey)-1 {
buf.WriteString(" -> ")
}
}
// print out the journey and the loop point.
fmt.Printf("Journey: %s\n", buf.String())
fmt.Printf("Loop Point: %s", circularReference.LoopPoint.Definition)
// Output: Journey: #/components/schemas/Two -> #/components/schemas/One -> #/components/schemas/Two
// Loop Point: #/components/schemas/Two
}
// This tests checks that circular references which are _not_ marked as required pass correctly
func TestNewDocument_terminable_circular_references(t *testing.T) {
// create a specification with an obvious and deliberate circular reference
spec := `openapi: "3.1"
components:
schemas:
One:
description: "test one"
properties:
things:
"$ref": "#/components/schemas/Two"
Two:
description: "test two"
properties:
testThing:
"$ref": "#/components/schemas/One"
`
// create a new document from specification bytes
doc, err := NewDocument([]byte(spec))
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
_, errs := doc.BuildV3Model()
assert.Len(t, errs, 0)
}
// If you're using complex types with OpenAPI Extensions, it's simple to unpack extensions into complex
// types using `high.UnpackExtensions()`. libopenapi retains the original raw data in the low model (not the high)
// which means unpacking them can be a little complex.
//
// This example demonstrates how to use the `UnpackExtensions` with custom OpenAPI extensions.
func ExampleNewDocument_unpacking_extensions() {
// define an example struct representing a cake
type cake struct {
Candles int `yaml:"candles"`
Frosting string `yaml:"frosting"`
Some_Strange_Var_Name string `yaml:"someStrangeVarName"`
}
// define a struct that holds a map of cake pointers.
type cakes struct {
Description string
Cakes map[string]*cake
}
// define a struct representing a burger
type burger struct {
Sauce string
Patty string
}
// define a struct that holds a map of cake pointers
type burgers struct {
Description string
Burgers map[string]*burger
}
// create a specification with a schema and parameter that use complex custom cakes and burgers extensions.
spec := `openapi: "3.1"
components:
schemas:
SchemaOne:
description: "Some schema with custom complex extensions"
x-custom-cakes:
description: some cakes
cakes:
someCake:
candles: 10
frosting: blue
someStrangeVarName: something
anotherCake:
candles: 1
frosting: green
parameters:
ParameterOne:
description: "Some parameter also using complex extensions"
x-custom-burgers:
description: some burgers
burgers:
someBurger:
sauce: ketchup
patty: meat
anotherBurger:
sauce: mayo
patty: lamb`
// create a new document from specification bytes
doc, err := NewDocument([]byte(spec))
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// build a v3 model.
docModel, errs := doc.BuildV3Model()
// if anything went wrong building, indexing and resolving the model, an error is thrown
if errs != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// get a reference to SchemaOne and ParameterOne
schemaOne := docModel.Model.Components.Schemas["SchemaOne"].Schema()
parameterOne := docModel.Model.Components.Parameters["ParameterOne"]
// unpack schemaOne extensions into complex `cakes` type
schemaOneExtensions, schemaUnpackErrors := high.UnpackExtensions[cakes, *low.Schema](schemaOne)
if schemaUnpackErrors != nil {
panic(fmt.Sprintf("cannot unpack schema extensions: %e", err))
}
// unpack parameterOne into complex `burgers` type
parameterOneExtensions, paramUnpackErrors := high.UnpackExtensions[burgers, *v3.Parameter](parameterOne)
if paramUnpackErrors != nil {
panic(fmt.Sprintf("cannot unpack parameter extensions: %e", err))
}
// extract extension by name for schemaOne
customCakes := schemaOneExtensions["x-custom-cakes"]
// extract extension by name for schemaOne
customBurgers := parameterOneExtensions["x-custom-burgers"]
// print out schemaOne complex extension details.
fmt.Printf("schemaOne 'x-custom-cakes' (%s) has %d cakes, 'someCake' has %d candles and %s frosting\n",
customCakes.Description,
len(customCakes.Cakes),
customCakes.Cakes["someCake"].Candles,
customCakes.Cakes["someCake"].Frosting,
)
// print out parameterOne complex extension details.
fmt.Printf("parameterOne 'x-custom-burgers' (%s) has %d burgers, 'anotherBurger' has %s sauce and a %s patty\n",
customBurgers.Description,
len(customBurgers.Burgers),
customBurgers.Burgers["anotherBurger"].Sauce,
customBurgers.Burgers["anotherBurger"].Patty,
)
// Output: schemaOne 'x-custom-cakes' (some cakes) has 2 cakes, 'someCake' has 10 candles and blue frosting
//parameterOne 'x-custom-burgers' (some burgers) has 2 burgers, 'anotherBurger' has mayo sauce and a lamb patty
}

View File

@@ -1,23 +1,15 @@
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT
package libopenapi
import (
"fmt"
"github.com/pb33f/libopenapi/datamodel"
"github.com/pb33f/libopenapi/datamodel/high/base"
"io/ioutil"
"net/url"
"strings"
"testing"
"github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/base"
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/resolver"
"github.com/pb33f/libopenapi/utils"
"github.com/pb33f/libopenapi/what-changed/model"
"github.com/stretchr/testify/assert"
"io/ioutil"
"os"
"testing"
)
func TestLoadDocument_Simple_V2(t *testing.T) {
@@ -158,6 +150,60 @@ info:
assert.Equal(t, ymlModified, string(serial))
}
func TestDocument_RenderAndReload_ChangeCheck_Burgershop(t *testing.T) {
bs, _ := ioutil.ReadFile("test_specs/burgershop.openapi.yaml")
doc, _ := NewDocument(bs)
doc.BuildV3Model()
rend, newDoc, _, _ := doc.RenderAndReload()
os.WriteFile("rendered-bs.yaml", rend, 0644)
// compare documents
compReport, errs := CompareDocuments(doc, newDoc)
// should noth be nil.
assert.Nil(t, errs)
assert.NotNil(t, rend)
assert.Nil(t, compReport)
}
func TestDocument_RenderAndReload_ChangeCheck_Stripe(t *testing.T) {
bs, _ := ioutil.ReadFile("test_specs/stripe.yaml")
doc, _ := NewDocument(bs)
doc.BuildV3Model()
b, newDoc, _, _ := doc.RenderAndReload()
os.WriteFile("rendered-data.yaml", b, 0644)
// compare documents
compReport, errs := CompareDocuments(doc, newDoc)
// get flat list of changes.
flatChanges := compReport.GetAllChanges()
// remove everything that is a description change (stripe has a lot of those from having 519 empty descriptions)
var filtered []*model.Change
for i := range flatChanges {
if flatChanges[i].Property != "description" {
filtered = append(filtered, flatChanges[i])
}
}
assert.Nil(t, errs)
tc := compReport.TotalChanges()
bc := compReport.TotalBreakingChanges()
assert.Equal(t, 0, bc)
assert.Equal(t, 519, tc)
// there should be no other changes than the 519 descriptions.
assert.Equal(t, 0, len(filtered))
}
func TestDocument_RenderAndReload(t *testing.T) {
// load an OpenAPI 3 specification from bytes
@@ -209,6 +255,41 @@ func TestDocument_RenderAndReload(t *testing.T) {
h.Components.SecuritySchemes["petstore_auth"].Flows.Implicit.AuthorizationUrl)
}
func TestDocument_RenderAndReload_Swagger(t *testing.T) {
petstore, _ := ioutil.ReadFile("test_specs/petstorev2.json")
doc, _ := NewDocument(petstore)
doc.BuildV2Model()
doc.BuildV2Model()
_, _, _, e := doc.RenderAndReload()
assert.Len(t, e, 1)
assert.Equal(t, "this method only supports OpenAPI 3 documents, not Swagger", e[0].Error())
}
func TestDocument_BuildModelPreBuild(t *testing.T) {
petstore, _ := ioutil.ReadFile("test_specs/petstorev3.json")
doc, _ := NewDocument(petstore)
doc.BuildV3Model()
doc.BuildV3Model()
_, _, _, e := doc.RenderAndReload()
assert.Len(t, e, 0)
}
func TestDocument_BuildModelCircular(t *testing.T) {
petstore, _ := ioutil.ReadFile("test_specs/circular-tests.yaml")
doc, _ := NewDocument(petstore)
m, e := doc.BuildV3Model()
assert.NotNil(t, m)
assert.Len(t, e, 3)
}
func TestDocument_BuildModelBad(t *testing.T) {
petstore, _ := ioutil.ReadFile("test_specs/badref-burgershop.openapi.yaml")
doc, _ := NewDocument(petstore)
m, e := doc.BuildV3Model()
assert.Nil(t, m)
assert.Len(t, e, 9)
}
func TestDocument_Serialize_JSON_Modified(t *testing.T) {
@@ -267,585 +348,49 @@ paths:
operation.GoLow().Parameters.Value[0].Reference)
}
func ExampleNewDocument_fromOpenAPI3Document() {
// How to read in an OpenAPI 3 Specification, into a Document.
// load an OpenAPI 3 specification from bytes
petstore, _ := ioutil.ReadFile("test_specs/petstorev3.json")
// create a new document from specification bytes
document, err := NewDocument(petstore)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// because we know this is a v3 spec, we can build a ready to go model from it.
v3Model, errors := document.BuildV3Model()
// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
for i := range errors {
fmt.Printf("error: %e\n", errors[i])
}
panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
}
// get a count of the number of paths and schemas.
paths := len(v3Model.Model.Paths.PathItems)
schemas := len(v3Model.Model.Components.Schemas)
// print the number of paths and schemas in the document
fmt.Printf("There are %d paths and %d schemas in the document", paths, schemas)
// Output: There are 13 paths and 8 schemas in the document
}
func ExampleNewDocument_fromWithDocumentConfigurationFailure() {
// This example shows how to create a document that prevents the loading of external references/
// from files or the network
// load in the Digital Ocean OpenAPI specification
digitalOcean, _ := ioutil.ReadFile("test_specs/digitalocean.yaml")
// create a DocumentConfiguration that prevents loading file and remote references
config := datamodel.DocumentConfiguration{
AllowFileReferences: false,
AllowRemoteReferences: false,
}
// create a new document from specification bytes
doc, err := NewDocumentWithConfiguration(digitalOcean, &config)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// only errors will be thrown, so just capture them and print the number of errors.
_, errors := doc.BuildV3Model()
// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
fmt.Println("Error building Digital Ocean spec errors reported")
}
// Output: Error building Digital Ocean spec errors reported
}
func ExampleNewDocument_fromWithDocumentConfigurationSuccess() {
// This example shows how to create a document that prevents the loading of external references/
// from files or the network
// load in the Digital Ocean OpenAPI specification
digitalOcean, _ := ioutil.ReadFile("test_specs/digitalocean.yaml")
// Digital Ocean needs a baseURL to be set, so we can resolve relative references.
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
// create a DocumentConfiguration that allows loading file and remote references, and sets the baseURL
// to somewhere that can resolve the relative references.
config := datamodel.DocumentConfiguration{
AllowFileReferences: true,
AllowRemoteReferences: true,
BaseURL: baseURL,
}
// create a new document from specification bytes
doc, err := NewDocumentWithConfiguration(digitalOcean, &config)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// only errors will be thrown, so just capture them and print the number of errors.
_, errors := doc.BuildV3Model()
// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
fmt.Println("Error building Digital Ocean spec errors reported")
} else {
fmt.Println("Digital Ocean spec built successfully")
}
// Output: Digital Ocean spec built successfully
}
func ExampleNewDocument_fromSwaggerDocument() {
// How to read in a Swagger / OpenAPI 2 Specification, into a Document.
// load a Swagger specification from bytes
petstore, _ := ioutil.ReadFile("test_specs/petstorev2.json")
// create a new document from specification bytes
document, err := NewDocument(petstore)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// because we know this is a v2 spec, we can build a ready to go model from it.
v2Model, errors := document.BuildV2Model()
// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
for i := range errors {
fmt.Printf("error: %e\n", errors[i])
}
panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
}
// get a count of the number of paths and schemas.
paths := len(v2Model.Model.Paths.PathItems)
schemas := len(v2Model.Model.Definitions.Definitions)
// print the number of paths and schemas in the document
fmt.Printf("There are %d paths and %d schemas in the document", paths, schemas)
// Output: There are 14 paths and 6 schemas in the document
}
func ExampleNewDocument_fromUnknownVersion() {
// load an unknown version of an OpenAPI spec
petstore, _ := ioutil.ReadFile("test_specs/burgershop.openapi.yaml")
// create a new document from specification bytes
document, err := NewDocument(petstore)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
var paths, schemas int
var errors []error
// We don't know which type of document this is, so we can use the spec info to inform us
if document.GetSpecInfo().SpecType == utils.OpenApi3 {
v3Model, errs := document.BuildV3Model()
if len(errs) > 0 {
errors = errs
}
if len(errors) <= 0 {
paths = len(v3Model.Model.Paths.PathItems)
schemas = len(v3Model.Model.Components.Schemas)
}
}
if document.GetSpecInfo().SpecType == utils.OpenApi2 {
v2Model, errs := document.BuildV2Model()
if len(errs) > 0 {
errors = errs
}
if len(errors) <= 0 {
paths = len(v2Model.Model.Paths.PathItems)
schemas = len(v2Model.Model.Definitions.Definitions)
}
}
// if anything went wrong when building the model, report errors.
if len(errors) > 0 {
for i := range errors {
fmt.Printf("error: %e\n", errors[i])
}
panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
}
// print the number of paths and schemas in the document
fmt.Printf("There are %d paths and %d schemas in the document", paths, schemas)
// Output: There are 5 paths and 6 schemas in the document
}
func ExampleNewDocument_mutateValuesAndSerialize() {
// How to mutate values in an OpenAPI Specification, without re-ordering original content.
// create very small, and useless spec that does nothing useful, except showcase this feature.
spec := `
openapi: 3.1.0
info:
title: This is a title
contact:
name: Some Person
email: some@emailaddress.com
license:
url: http://some-place-on-the-internet.com/license
`
// create a new document from specification bytes
document, err := NewDocument([]byte(spec))
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// because we know this is a v3 spec, we can build a ready to go model from it.
v3Model, errors := document.BuildV3Model()
// if anything went wrong when building the v3 model, a slice of errors will be returned
if len(errors) > 0 {
for i := range errors {
fmt.Printf("error: %e\n", errors[i])
}
panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
}
// mutate the title, to do this we currently need to drop down to the low-level API.
v3Model.Model.GoLow().Info.Value.Title.Mutate("A new title for a useless spec")
// mutate the email address in the contact object.
v3Model.Model.GoLow().Info.Value.Contact.Value.Email.Mutate("buckaroo@pb33f.io")
// mutate the name in the contact object.
v3Model.Model.GoLow().Info.Value.Contact.Value.Name.Mutate("Buckaroo")
// mutate the URL for the license object.
v3Model.Model.GoLow().Info.Value.License.Value.URL.Mutate("https://pb33f.io/license")
// serialize the document back into the original YAML or JSON
mutatedSpec, serialError := document.Serialize()
// if something went wrong serializing
if serialError != nil {
panic(fmt.Sprintf("cannot serialize document: %e", serialError))
}
// print our modified spec!
fmt.Println(string(mutatedSpec))
// Output: openapi: 3.1.0
//info:
// title: A new title for a useless spec
// contact:
// name: Buckaroo
// email: buckaroo@pb33f.io
// license:
// url: https://pb33f.io/license
}
func ExampleCompareDocuments_openAPI() {
// How to compare two different OpenAPI specifications.
// load an original OpenAPI 3 specification from bytes
burgerShopOriginal, _ := ioutil.ReadFile("test_specs/burgershop.openapi.yaml")
// load an **updated** OpenAPI 3 specification from bytes
func TestDocument_BuildModel_CompareDocsV3_LeftError(t *testing.T) {
burgerShopOriginal, _ := ioutil.ReadFile("test_specs/badref-burgershop.openapi.yaml")
burgerShopUpdated, _ := ioutil.ReadFile("test_specs/burgershop.openapi-modified.yaml")
originalDoc, _ := NewDocument(burgerShopOriginal)
updatedDoc, _ := NewDocument(burgerShopUpdated)
changes, errors := CompareDocuments(originalDoc, updatedDoc)
assert.Len(t, errors, 9)
assert.Nil(t, changes)
}
// create a new document from original specification bytes
originalDoc, err := NewDocument(burgerShopOriginal)
func TestDocument_BuildModel_CompareDocsV3_RightError(t *testing.T) {
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// create a new document from updated specification bytes
updatedDoc, err := NewDocument(burgerShopUpdated)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// Compare documents for all changes made
documentChanges, errs := CompareDocuments(originalDoc, updatedDoc)
// If anything went wrong when building models for documents.
if len(errs) > 0 {
for i := range errs {
fmt.Printf("error: %e\n", errs[i])
}
panic(fmt.Sprintf("cannot compare documents: %d errors reported", len(errs)))
}
// Extract SchemaChanges from components changes.
schemaChanges := documentChanges.ComponentsChanges.SchemaChanges
// Print out some interesting stats about the OpenAPI document changes.
fmt.Printf("There are %d changes, of which %d are breaking. %v schemas have changes.",
documentChanges.TotalChanges(), documentChanges.TotalBreakingChanges(), len(schemaChanges))
//Output: There are 72 changes, of which 17 are breaking. 5 schemas have changes.
burgerShopOriginal, _ := ioutil.ReadFile("test_specs/badref-burgershop.openapi.yaml")
burgerShopUpdated, _ := ioutil.ReadFile("test_specs/burgershop.openapi-modified.yaml")
originalDoc, _ := NewDocument(burgerShopOriginal)
updatedDoc, _ := NewDocument(burgerShopUpdated)
changes, errors := CompareDocuments(updatedDoc, originalDoc)
assert.Len(t, errors, 9)
assert.Nil(t, changes)
}
func ExampleCompareDocuments_swagger() {
func TestDocument_BuildModel_CompareDocsV2_Error(t *testing.T) {
// How to compare two different Swagger specifications.
// load an original OpenAPI 3 specification from bytes
petstoreOriginal, _ := ioutil.ReadFile("test_specs/petstorev2-complete.yaml")
// load an **updated** OpenAPI 3 specification from bytes
petstoreUpdated, _ := ioutil.ReadFile("test_specs/petstorev2-complete-modified.yaml")
// create a new document from original specification bytes
originalDoc, err := NewDocument(petstoreOriginal)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// create a new document from updated specification bytes
updatedDoc, err := NewDocument(petstoreUpdated)
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// Compare documents for all changes made
documentChanges, errs := CompareDocuments(originalDoc, updatedDoc)
// If anything went wrong when building models for documents.
if len(errs) > 0 {
for i := range errs {
fmt.Printf("error: %e\n", errs[i])
}
panic(fmt.Sprintf("cannot compare documents: %d errors reported", len(errs)))
}
// Extract SchemaChanges from components changes.
schemaChanges := documentChanges.ComponentsChanges.SchemaChanges
// Print out some interesting stats about the Swagger document changes.
fmt.Printf("There are %d changes, of which %d are breaking. %v schemas have changes.",
documentChanges.TotalChanges(), documentChanges.TotalBreakingChanges(), len(schemaChanges))
//Output: There are 52 changes, of which 27 are breaking. 5 schemas have changes.
burgerShopOriginal, _ := ioutil.ReadFile("test_specs/petstorev2-badref.json")
burgerShopUpdated, _ := ioutil.ReadFile("test_specs/petstorev2-badref.json")
originalDoc, _ := NewDocument(burgerShopOriginal)
updatedDoc, _ := NewDocument(burgerShopUpdated)
changes, errors := CompareDocuments(updatedDoc, originalDoc)
assert.Len(t, errors, 2)
assert.Nil(t, changes)
}
func TestDocument_Paths_As_Array(t *testing.T) {
func TestDocument_BuildModel_CompareDocsV2V3Mix_Error(t *testing.T) {
// paths can now be wrapped in an array.
spec := `{
"openapi": "3.1.0",
"paths": [
"/": {
"get": {}
}
]
}
`
// create a new document from specification bytes
doc, err := NewDocument([]byte(spec))
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
v3Model, _ := doc.BuildV3Model()
assert.NotNil(t, v3Model)
}
// If you want to know more about circular references that have been found
// during the parsing/indexing/building of a document, you can capture the
// []errors thrown which are pointers to *resolver.ResolvingError
func ExampleNewDocument_infinite_circular_references() {
// create a specification with an obvious and deliberate circular reference
spec := `openapi: "3.1"
components:
schemas:
One:
description: "test one"
properties:
things:
"$ref": "#/components/schemas/Two"
required:
- things
Two:
description: "test two"
properties:
testThing:
"$ref": "#/components/schemas/One"
required:
- testThing
`
// create a new document from specification bytes
doc, err := NewDocument([]byte(spec))
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
_, errs := doc.BuildV3Model()
// extract resolving error
resolvingError := errs[0]
// resolving error is a pointer to *resolver.ResolvingError
// which provides access to rich details about the error.
circularReference := resolvingError.(*resolver.ResolvingError).CircularReference
// capture the journey with all details
var buf strings.Builder
for n := range circularReference.Journey {
// add the full definition name to the journey.
buf.WriteString(circularReference.Journey[n].Definition)
if n < len(circularReference.Journey)-1 {
buf.WriteString(" -> ")
}
}
// print out the journey and the loop point.
fmt.Printf("Journey: %s\n", buf.String())
fmt.Printf("Loop Point: %s", circularReference.LoopPoint.Definition)
// Output: Journey: #/components/schemas/Two -> #/components/schemas/One -> #/components/schemas/Two
// Loop Point: #/components/schemas/Two
}
// This tests checks that circular references which are _not_ marked as required pass correctly
func TestNewDocument_terminable_circular_references(t *testing.T) {
// create a specification with an obvious and deliberate circular reference
spec := `openapi: "3.1"
components:
schemas:
One:
description: "test one"
properties:
things:
"$ref": "#/components/schemas/Two"
Two:
description: "test two"
properties:
testThing:
"$ref": "#/components/schemas/One"
`
// create a new document from specification bytes
doc, err := NewDocument([]byte(spec))
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
_, errs := doc.BuildV3Model()
assert.Len(t, errs, 0)
}
// If you're using complex types with OpenAPI Extensions, it's simple to unpack extensions into complex
// types using `high.UnpackExtensions()`. libopenapi retains the original raw data in the low model (not the high)
// which means unpacking them can be a little complex.
//
// This example demonstrates how to use the `UnpackExtensions` with custom OpenAPI extensions.
func ExampleNewDocument_unpacking_extensions() {
// define an example struct representing a cake
type cake struct {
Candles int `yaml:"candles"`
Frosting string `yaml:"frosting"`
Some_Strange_Var_Name string `yaml:"someStrangeVarName"`
}
// define a struct that holds a map of cake pointers.
type cakes struct {
Description string
Cakes map[string]*cake
}
// define a struct representing a burger
type burger struct {
Sauce string
Patty string
}
// define a struct that holds a map of cake pointers
type burgers struct {
Description string
Burgers map[string]*burger
}
// create a specification with a schema and parameter that use complex custom cakes and burgers extensions.
spec := `openapi: "3.1"
components:
schemas:
SchemaOne:
description: "Some schema with custom complex extensions"
x-custom-cakes:
description: some cakes
cakes:
someCake:
candles: 10
frosting: blue
someStrangeVarName: something
anotherCake:
candles: 1
frosting: green
parameters:
ParameterOne:
description: "Some parameter also using complex extensions"
x-custom-burgers:
description: some burgers
burgers:
someBurger:
sauce: ketchup
patty: meat
anotherBurger:
sauce: mayo
patty: lamb`
// create a new document from specification bytes
doc, err := NewDocument([]byte(spec))
// if anything went wrong, an error is thrown
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// build a v3 model.
docModel, errs := doc.BuildV3Model()
// if anything went wrong building, indexing and resolving the model, an error is thrown
if errs != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}
// get a reference to SchemaOne and ParameterOne
schemaOne := docModel.Model.Components.Schemas["SchemaOne"].Schema()
parameterOne := docModel.Model.Components.Parameters["ParameterOne"]
// unpack schemaOne extensions into complex `cakes` type
schemaOneExtensions, schemaUnpackErrors := high.UnpackExtensions[cakes, *low.Schema](schemaOne)
if schemaUnpackErrors != nil {
panic(fmt.Sprintf("cannot unpack schema extensions: %e", err))
}
// unpack parameterOne into complex `burgers` type
parameterOneExtensions, paramUnpackErrors := high.UnpackExtensions[burgers, *v3.Parameter](parameterOne)
if paramUnpackErrors != nil {
panic(fmt.Sprintf("cannot unpack parameter extensions: %e", err))
}
// extract extension by name for schemaOne
customCakes := schemaOneExtensions["x-custom-cakes"]
// extract extension by name for schemaOne
customBurgers := parameterOneExtensions["x-custom-burgers"]
// print out schemaOne complex extension details.
fmt.Printf("schemaOne 'x-custom-cakes' (%s) has %d cakes, 'someCake' has %d candles and %s frosting\n",
customCakes.Description,
len(customCakes.Cakes),
customCakes.Cakes["someCake"].Candles,
customCakes.Cakes["someCake"].Frosting,
)
// print out parameterOne complex extension details.
fmt.Printf("parameterOne 'x-custom-burgers' (%s) has %d burgers, 'anotherBurger' has %s sauce and a %s patty\n",
customBurgers.Description,
len(customBurgers.Burgers),
customBurgers.Burgers["anotherBurger"].Sauce,
customBurgers.Burgers["anotherBurger"].Patty,
)
// Output: schemaOne 'x-custom-cakes' (some cakes) has 2 cakes, 'someCake' has 10 candles and blue frosting
//parameterOne 'x-custom-burgers' (some burgers) has 2 burgers, 'anotherBurger' has mayo sauce and a lamb patty
burgerShopOriginal, _ := ioutil.ReadFile("test_specs/petstorev2.json")
burgerShopUpdated, _ := ioutil.ReadFile("test_specs/petstorev3.json")
originalDoc, _ := NewDocument(burgerShopOriginal)
updatedDoc, _ := NewDocument(burgerShopUpdated)
changes, errors := CompareDocuments(updatedDoc, originalDoc)
assert.Len(t, errors, 1)
assert.Nil(t, changes)
}

View File

@@ -72,10 +72,10 @@ func (resolver *Resolver) GetPolymorphicCircularErrors() []*index.CircularRefere
if !resolver.circularReferences[i].IsInfiniteLoop {
continue
}
if resolver.circularReferences[i].IsPolymorphicResult {
res = append(res, resolver.circularReferences[i])
if !resolver.circularReferences[i].IsPolymorphicResult {
continue
}
res = append(res, resolver.circularReferences[i])
}
return res
}

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"io/ioutil"
"net/url"
"testing"
"github.com/pb33f/libopenapi/index"
@@ -62,6 +63,31 @@ func TestResolver_CheckForCircularReferences(t *testing.T) {
assert.NoError(t, err)
}
func TestResolver_CheckForCircularReferences_DigitalOcean(t *testing.T) {
circular, _ := ioutil.ReadFile("../test_specs/digitalocean.yaml")
var rootNode yaml.Node
yaml.Unmarshal(circular, &rootNode)
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
index := index.NewSpecIndexWithConfig(&rootNode, &index.SpecIndexConfig{
AllowRemoteLookup: true,
AllowFileLookup: true,
BaseURL: baseURL,
})
resolver := NewResolver(index)
assert.NotNil(t, resolver)
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 0)
assert.Len(t, resolver.GetResolvingErrors(), 0)
assert.Len(t, resolver.GetCircularErrors(), 0)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
}
func TestResolver_CircularReferencesRequiredValid(t *testing.T) {
circular, _ := ioutil.ReadFile("../test_specs/swagger-valid-recursive-model.yaml")
var rootNode yaml.Node
@@ -170,6 +196,37 @@ components:
assert.Len(t, circ, 0)
}
func TestResolver_ResolveComponents_PolyCircRef(t *testing.T) {
yml := `openapi: 3.1.0
components:
schemas:
cheese:
description: cheese
anyOf:
- $ref: '#/components/schemas/crackers'
crackers:
description: crackers
anyOf:
- $ref: '#/components/schemas/cheese'
tea:
description: tea`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
index := index.NewSpecIndex(&rootNode)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
_ = resolver.CheckForCircularReferences()
resolver.circularReferences[0].IsInfiniteLoop = true // override
assert.Len(t, index.GetCircularReferences(), 1)
assert.Len(t, resolver.GetPolymorphicCircularErrors(), 1)
assert.Equal(t, 2, index.GetCircularReferences()[0].LoopIndex)
}
func TestResolver_ResolveComponents_Missing(t *testing.T) {
yml := `paths:
/hey:

File diff suppressed because it is too large Load Diff

View File

@@ -20721,6 +20721,7 @@ components:
type: object
x-expandableFields: []
refund:
description: |-
description: |-
`Refund` objects allow you to refund a charge that has previously been created
but not yet refunded. Funds will be refunded to the credit or debit card that

View File

@@ -5,6 +5,15 @@ package utils
import "gopkg.in/yaml.v3"
func CreateRefNode(ref string) *yaml.Node {
m := CreateEmptyMapNode()
nodes := make([]*yaml.Node, 2)
nodes[0] = CreateStringNode("$ref")
nodes[1] = CreateStringNode(ref)
m.Content = nodes
return m
}
func CreateEmptyMapNode() *yaml.Node {
n := &yaml.Node{
Kind: yaml.MappingNode,

49
utils/nodes_test.go Normal file
View File

@@ -0,0 +1,49 @@
// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT
package utils
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestCreateBoolNode(t *testing.T) {
b := CreateBoolNode("true")
assert.Equal(t, "!!bool", b.Tag)
assert.Equal(t, "true", b.Value)
}
func TestCreateEmptyMapNode(t *testing.T) {
m := CreateEmptyMapNode()
assert.Equal(t, "!!map", m.Tag)
assert.Len(t, m.Content, 0)
}
func TestCreateEmptySequenceNode(t *testing.T) {
s := CreateEmptySequenceNode()
assert.Equal(t, "!!seq", s.Tag)
assert.Len(t, s.Content, 0)
}
func TestCreateFloatNode(t *testing.T) {
f := CreateFloatNode("3.14")
assert.Equal(t, "!!float", f.Tag)
assert.Equal(t, "3.14", f.Value)
}
func TestCreateIntNode(t *testing.T) {
i := CreateIntNode("42")
assert.Equal(t, "!!int", i.Tag)
assert.Equal(t, "42", i.Value)
}
func TestCreateRefNode(t *testing.T) {
r := CreateRefNode("#/components/schemas/MySchema")
assert.Equal(t, "!!map", r.Tag)
assert.Len(t, r.Content, 2)
assert.Equal(t, "!!str", r.Content[0].Tag)
assert.Equal(t, "$ref", r.Content[0].Value)
assert.Equal(t, "!!str", r.Content[1].Tag)
assert.Equal(t, "#/components/schemas/MySchema", r.Content[1].Value)
}

View File

@@ -27,6 +27,19 @@ func (c *CallbackChanges) TotalChanges() int {
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
}
// TotalBreakingChanges returns a total count of all changes made between Callback objects
func (c *CallbackChanges) TotalBreakingChanges() int {
d := c.PropertyChanges.TotalBreakingChanges()

View File

@@ -87,6 +87,7 @@ func TestCompareCallback_Add(t *testing.T) {
// compare.
extChanges := CompareCallback(&lDoc, &rDoc)
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
@@ -138,6 +139,7 @@ func TestCompareCallback_Modify(t *testing.T) {
// compare.
extChanges := CompareCallback(&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.ExpressionChanges["{$request.query.queryUrl}"].Changes[0].ChangeType)
assert.Equal(t, v3.GetLabel, extChanges.ExpressionChanges["{$request.query.queryUrl}"].Changes[0].Property)
@@ -187,6 +189,7 @@ func TestCompareCallback_Remove(t *testing.T) {
// compare.
extChanges := CompareCallback(&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, "slippers", extChanges.Changes[0].Property)

View File

@@ -50,15 +50,15 @@ 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.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
}
//if (c.NewColumn == nil && c.OriginalColumn != nil) || (c.NewColumn != nil && c.OriginalColumn == nil) {
// return true
//}
return false
}

View File

@@ -235,6 +235,22 @@ func runComparison[T any, R any](l, r map[low.KeyReference[string]]low.ValueRefe
}
}
// GetAllChanges returns a slice of all changes made between Callback objects
func (c *ComponentsChanges) GetAllChanges() []*Change {
var changes []*Change
changes = append(changes, c.Changes...)
for k := range c.SchemaChanges {
changes = append(changes, c.SchemaChanges[k].GetAllChanges()...)
}
for k := range c.SecuritySchemeChanges {
changes = append(changes, c.SecuritySchemeChanges[k].GetAllChanges()...)
}
if c.ExtensionChanges != nil {
changes = append(changes, c.ExtensionChanges.GetAllChanges()...)
}
return changes
}
// TotalChanges returns total changes for all Components and Definitions
func (c *ComponentsChanges) TotalChanges() int {
v := c.PropertyChanges.TotalChanges()

View File

@@ -75,6 +75,7 @@ thing2:
// compare.
extChanges := CompareComponents(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -113,6 +114,7 @@ thing3:
// compare.
extChanges := CompareComponents(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
@@ -152,6 +154,7 @@ thing3:
// compare.
extChanges := CompareComponents(&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, "thing3", extChanges.Changes[0].Original)
@@ -190,6 +193,7 @@ param4:
// compare.
extChanges := CompareComponents(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
assert.Equal(t, "param4", extChanges.Changes[0].New)
@@ -228,6 +232,7 @@ param4:
// compare.
extChanges := CompareComponents(&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, "param4", extChanges.Changes[0].Original)
@@ -263,6 +268,7 @@ resp3:
extChanges := CompareComponents(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, "resp3", extChanges.Changes[0].New)
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
@@ -299,6 +305,7 @@ resp3:
extChanges := CompareComponents(&rDoc, &lDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
assert.Equal(t, "resp3", extChanges.Changes[0].Original)
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
@@ -330,6 +337,7 @@ scheme2:
// compare.
extChanges := CompareComponents(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, 1, extChanges.SecuritySchemeChanges["scheme1"].TotalChanges())
assert.Equal(t, v3.DescriptionLabel, extChanges.SecuritySchemeChanges["scheme1"].Changes[0].Property)
@@ -1088,4 +1096,5 @@ func TestCompareComponents_OpenAPI_Extensions_Modified(t *testing.T) {
// compare.
extChanges := CompareComponents(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
}

View File

@@ -13,6 +13,11 @@ type ContactChanges struct {
*PropertyChanges
}
// GetAllChanges returns a slice of all changes made between Callback objects
func (c *ContactChanges) GetAllChanges() []*Change {
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()

View File

@@ -33,6 +33,7 @@ url: https://pb33f.io`
// compare.
extChanges := CompareContact(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
}

View File

@@ -26,6 +26,16 @@ func (d *DiscriminatorChanges) TotalChanges() int {
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
}
// TotalBreakingChanges returns the number of breaking changes made by the Discriminator
func (d *DiscriminatorChanges) TotalBreakingChanges() int {
return d.PropertyChanges.TotalBreakingChanges() + CountBreakingChanges(d.MappingChanges)

View File

@@ -30,6 +30,7 @@ func TestCompareDiscriminator_PropertyNameChanged(t *testing.T) {
// compare.
extChanges := CompareDiscriminator(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
}
@@ -56,6 +57,7 @@ propertyName: chicken`
// compare.
extChanges := CompareDiscriminator(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
}
@@ -81,6 +83,7 @@ propertyName: chicken`
// compare.
extChanges := CompareDiscriminator(&rDoc, &lDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
}
@@ -106,6 +109,7 @@ mapping:
// compare.
extChanges := CompareDiscriminator(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
for _, k := range extChanges.MappingChanges {
assert.Equal(t, ObjectAdded, k.ChangeType)

View File

@@ -66,6 +66,40 @@ func (d *DocumentChanges) TotalChanges() int {
return c
}
// GetAllChanges returns a slice of all changes made between Document objects
func (d *DocumentChanges) GetAllChanges() []*Change {
var changes []*Change
changes = append(changes, d.Changes...)
if d.InfoChanges != nil {
changes = append(changes, d.InfoChanges.GetAllChanges()...)
}
if d.PathsChanges != nil {
changes = append(changes, d.PathsChanges.GetAllChanges()...)
}
for k := range d.TagChanges {
changes = append(changes, d.TagChanges[k].GetAllChanges()...)
}
if d.ExternalDocChanges != nil {
changes = append(changes, d.ExternalDocChanges.GetAllChanges()...)
}
for k := range d.WebhookChanges {
changes = append(changes, d.WebhookChanges[k].GetAllChanges()...)
}
for k := range d.ServerChanges {
changes = append(changes, d.ServerChanges[k].GetAllChanges()...)
}
for k := range d.SecurityRequirementChanges {
changes = append(changes, d.SecurityRequirementChanges[k].GetAllChanges()...)
}
if d.ComponentsChanges != nil {
changes = append(changes, d.ComponentsChanges.GetAllChanges()...)
}
if d.ExtensionChanges != nil {
changes = append(changes, d.ExtensionChanges.GetAllChanges()...)
}
return changes
}
// TotalBreakingChanges returns a total count of all breaking changes made in the Document
func (d *DocumentChanges) TotalBreakingChanges() int {
c := d.PropertyChanges.TotalBreakingChanges()

View File

@@ -85,6 +85,7 @@ produces:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 10, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 10)
assert.Equal(t, 6, extChanges.TotalBreakingChanges())
}
@@ -113,6 +114,7 @@ produces:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 3, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 3)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
@@ -141,6 +143,7 @@ basePath: /api`
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 3, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 3)
assert.Equal(t, 3, extChanges.TotalBreakingChanges())
}
@@ -171,6 +174,7 @@ info:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 3, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 3)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, 3, extChanges.InfoChanges.TotalChanges())
}
@@ -196,6 +200,7 @@ info:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, v3.InfoLabel, extChanges.Changes[0].Property)
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
@@ -222,6 +227,7 @@ info:
// compare.
extChanges := CompareDocuments(rDoc, lDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, v3.InfoLabel, extChanges.Changes[0].Property)
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
@@ -248,6 +254,7 @@ externalDocs:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, 2, extChanges.ExternalDocChanges.TotalChanges())
}
@@ -270,6 +277,7 @@ externalDocs:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, v3.ExternalDocsLabel, extChanges.Changes[0].Property)
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
@@ -294,6 +302,7 @@ externalDocs:
// compare.
extChanges := CompareDocuments(rDoc, lDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, v3.ExternalDocsLabel, extChanges.Changes[0].Property)
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
@@ -367,6 +376,7 @@ security:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 4, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 4)
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
}
@@ -399,6 +409,7 @@ definitions:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 4, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 4)
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
}
@@ -459,6 +470,7 @@ securityDefinitions:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -527,6 +539,7 @@ parameters:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
@@ -594,6 +607,7 @@ responses:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -657,6 +671,7 @@ paths:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 3, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 3)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -689,6 +704,7 @@ paths:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 4, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 4)
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
}
@@ -748,6 +764,7 @@ tags:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 3, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 3)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
@@ -801,6 +818,7 @@ jsonSchemaDialect: https://pb33f.io/schema/changed`
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 3, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 3)
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
}
@@ -829,6 +847,7 @@ components:
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
}
@@ -858,6 +877,7 @@ components:
extChanges := CompareDocuments(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)
}
@@ -897,6 +917,7 @@ paths:
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
@@ -969,6 +990,7 @@ components:
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
@@ -1000,6 +1022,7 @@ servers:
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 3, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 3)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -1034,6 +1057,7 @@ components:
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
@@ -1072,6 +1096,7 @@ webhooks:
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
@@ -1114,6 +1139,7 @@ paths:
// compare.
extChanges := CompareDocuments(lDoc, rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}

View File

@@ -13,6 +13,16 @@ type EncodingChanges struct {
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
}
// TotalChanges returns the total number of changes made between two Encoding objects
func (e *EncodingChanges) TotalChanges() int {
c := e.PropertyChanges.TotalChanges()

View File

@@ -80,6 +80,7 @@ allowReserved: true`
extChanges := CompareEncoding(&lDoc, &rDoc)
assert.NotNil(t, extChanges)
assert.Equal(t, 4, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 4)
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
}
@@ -114,6 +115,7 @@ allowReserved: true`
extChanges := CompareEncoding(&lDoc, &rDoc)
assert.NotNil(t, extChanges)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
assert.Equal(t, v3.HeadersLabel, extChanges.Changes[0].Property)
@@ -149,6 +151,7 @@ allowReserved: true`
extChanges := CompareEncoding(&rDoc, &lDoc)
assert.NotNil(t, extChanges)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}

View File

@@ -21,6 +21,16 @@ type ExampleChanges struct {
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
}
// GetAllChanges returns a slice of all changes made between Example objects
func (e *ExampleChanges) GetAllChanges() []*Change {
var changes []*Change
changes = append(changes, e.Changes...)
if e.ExtensionChanges != nil {
changes = append(changes, e.ExtensionChanges.GetAllChanges()...)
}
return changes
}
// TotalChanges returns the total number of changes made to Example
func (e *ExampleChanges) TotalChanges() int {
l := e.PropertyChanges.TotalChanges()

View File

@@ -34,6 +34,7 @@ func TestCompareExamples_SummaryModified(t *testing.T) {
extChanges := CompareExamples(&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)
@@ -66,6 +67,7 @@ func TestCompareExamples_Map(t *testing.T) {
extChanges := CompareExamples(&lDoc, &rDoc)
assert.Equal(t, extChanges.TotalChanges(), 2)
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
}
@@ -94,6 +96,7 @@ func TestCompareExamples_MapAdded(t *testing.T) {
extChanges := CompareExamples(&lDoc, &rDoc)
assert.Equal(t, extChanges.TotalChanges(), 1)
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
}
@@ -147,6 +150,7 @@ description: cure all`
extChanges := CompareExamples(&lDoc, &rDoc)
assert.Equal(t, extChanges.TotalChanges(), 1)
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
assert.Equal(t, v3.DescriptionLabel, extChanges.Changes[0].Property)
assert.Equal(t, "cure all", extChanges.Changes[0].New)
@@ -173,6 +177,7 @@ x-herbs: cure all`
extChanges := CompareExamples(&lDoc, &rDoc)
assert.Equal(t, extChanges.TotalChanges(), 1)
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, ObjectAdded, extChanges.ExtensionChanges.Changes[0].ChangeType)
assert.Equal(t, "x-herbs", extChanges.ExtensionChanges.Changes[0].Property)
assert.Equal(t, "cure all", extChanges.ExtensionChanges.Changes[0].New)

View File

@@ -13,6 +13,11 @@ type ExamplesChanges struct {
*PropertyChanges
}
// GetAllChanges returns a slice of all changes made between Examples objects
func (a *ExamplesChanges) GetAllChanges() []*Change {
return a.Changes
}
// TotalChanges represents the total number of changes made between Example instances.
func (a *ExamplesChanges) TotalChanges() int {
return a.PropertyChanges.TotalChanges()

View File

@@ -31,6 +31,7 @@ func TestCompareExamplesV2(t *testing.T) {
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)
@@ -58,6 +59,7 @@ yummy: coffee`
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)
}
@@ -82,6 +84,7 @@ yummy: coffee`
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)
}

View File

@@ -13,6 +13,11 @@ type ExtensionChanges struct {
*PropertyChanges
}
// GetAllChanges returns a slice of all changes made between Extension objects
func (e *ExtensionChanges) GetAllChanges() []*Change {
return e.Changes
}
// TotalChanges returns the total number of object extensions that were made.
func (e *ExtensionChanges) TotalChanges() int {
return e.PropertyChanges.TotalChanges()

View File

@@ -25,6 +25,7 @@ func TestCompareExtensions(t *testing.T) {
extChanges := CompareExtensions(lExt, rExt)
assert.Equal(t, extChanges.TotalChanges(), 1)
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
assert.Equal(t, "1", extChanges.Changes[0].Original)
assert.Equal(t, "2", extChanges.Changes[0].New)
@@ -49,6 +50,7 @@ x-test: 1`
extChanges := CompareExtensions(lExt, rExt)
assert.Len(t, extChanges.Changes, 1)
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
assert.Equal(t, 2, *extChanges.Changes[0].Context.OriginalLine)
assert.Nil(t, extChanges.Changes[0].Context.NewLine)
@@ -73,6 +75,7 @@ x-test: 1`
extChanges := CompareExtensions(lExt, rExt)
assert.Len(t, extChanges.Changes, 1)
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
assert.Nil(t, extChanges.Changes[0].Context.OriginalLine)
assert.Equal(t, 2, *extChanges.Changes[0].Context.NewLine)

View File

@@ -14,6 +14,16 @@ type ExternalDocChanges struct {
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
}
// TotalChanges returns a count of everything that changed
func (e *ExternalDocChanges) TotalChanges() int {
c := e.PropertyChanges.TotalChanges()

View File

@@ -38,6 +38,7 @@ x-testing: hiya!`
extChanges := CompareExternalDocs(&lDoc, &rDoc)
assert.Len(t, extChanges.ExtensionChanges.Changes, 1)
assert.Len(t, extChanges.Changes, 2)
assert.Len(t, extChanges.GetAllChanges(), 3)
assert.Equal(t, 3, extChanges.TotalChanges())
// validate property changes
@@ -94,6 +95,7 @@ url: https://quobix.com`
extChanges := CompareExternalDocs(&lDoc, &rDoc)
assert.Len(t, extChanges.ExtensionChanges.Changes, 1)
assert.Len(t, extChanges.Changes, 2)
assert.Len(t, extChanges.GetAllChanges(), 3)
// validate property changes
urlChange := extChanges.Changes[0]
@@ -169,6 +171,7 @@ x-testing: hello`
// compare.
extChanges := CompareExternalDocs(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
}
@@ -194,6 +197,7 @@ url: https://pb33f.io`
// compare.
extChanges := CompareExternalDocs(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
}
@@ -219,6 +223,7 @@ description: something`
// compare.
extChanges := CompareExternalDocs(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
}
@@ -244,5 +249,6 @@ url: https://pb33f.io`
// compare
extChanges := CompareExternalDocs(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
}

View File

@@ -23,6 +23,28 @@ type HeaderChanges struct {
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
}
// TotalChanges returns the total number of changes made between two Header objects.
func (h *HeaderChanges) TotalChanges() int {
c := h.PropertyChanges.TotalChanges()

View File

@@ -123,6 +123,7 @@ x-beer: really yummy`
extChanges := CompareHeadersV2(&lDoc, &rDoc)
assert.NotNil(t, extChanges)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -167,6 +168,7 @@ x-beer: yummy`
assert.NotNil(t, extChanges)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
}
@@ -211,6 +213,7 @@ x-beer: yummy`
assert.NotNil(t, extChanges)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
}
@@ -301,6 +304,7 @@ x-beer: yummy`
extChanges := CompareHeadersV3(&lDoc, &rDoc)
assert.NotNil(t, extChanges)
assert.Equal(t, 5, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 5)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}

View File

@@ -15,6 +15,19 @@ type InfoChanges struct {
LicenseChanges *LicenseChanges `json:"license,omitempty" yaml:"license,omitempty"`
}
// 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
}
// TotalChanges represents the total number of changes made to an Info object.
func (i *InfoChanges) TotalChanges() int {
t := i.PropertyChanges.TotalChanges()

View File

@@ -48,6 +48,7 @@ license:
// 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)
}
@@ -88,6 +89,7 @@ license:
// 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)
}
@@ -127,6 +129,7 @@ license:
// 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)
}
@@ -164,6 +167,7 @@ contact:
// 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)
}
@@ -201,6 +205,7 @@ license:
// 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)
}
@@ -240,6 +245,7 @@ license:
// 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)
}
@@ -276,6 +282,7 @@ license:
// 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)
}
@@ -312,6 +319,7 @@ license:
// 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)
}
@@ -351,6 +359,7 @@ license:
// 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())

View File

@@ -15,6 +15,16 @@ type ItemsChanges struct {
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
}
// 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 {

View File

@@ -34,6 +34,7 @@ func TestCompareItems(t *testing.T) {
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)
}
@@ -64,6 +65,7 @@ items:
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)
@@ -93,6 +95,7 @@ items:
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)
@@ -122,6 +125,7 @@ items:
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)

View File

@@ -13,6 +13,11 @@ type LicenseChanges struct {
*PropertyChanges
}
// GetAllChanges returns a slice of all changes made between License objects
func (l *LicenseChanges) GetAllChanges() []*Change {
return l.Changes
}
// TotalChanges represents the total number of changes made to a License instance.
func (l *LicenseChanges) TotalChanges() int {
return l.PropertyChanges.TotalChanges()

View File

@@ -33,6 +33,7 @@ url: https://pb33f.io`
// compare.
extChanges := CompareLicense(&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, 0, extChanges.TotalBreakingChanges())
@@ -60,6 +61,7 @@ url: https://pb33f.io`
// compare.
extChanges := CompareLicense(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
}
@@ -86,6 +88,7 @@ name: buckaroo`
// compare.
extChanges := CompareLicense(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
}
@@ -112,6 +115,7 @@ name: buckaroo`
// compare.
extChanges := CompareLicense(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
}
@@ -137,6 +141,7 @@ func TestCompareLicense_URLModified(t *testing.T) {
// compare.
extChanges := CompareLicense(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
}
@@ -163,6 +168,7 @@ url: https://pb33f.io`
// compare.
extChanges := CompareLicense(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
assert.Equal(t, PropertyRemoved, extChanges.Changes[1].ChangeType)
}

View File

@@ -15,6 +15,19 @@ type LinkChanges struct {
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
}
// TotalChanges returns the total changes made between OpenAPI Link objects
func (l *LinkChanges) TotalChanges() int {
c := l.PropertyChanges.TotalChanges()

View File

@@ -76,6 +76,7 @@ x-cake: very tasty`
// 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)
@@ -114,6 +115,7 @@ parameters:
// 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)
}
@@ -149,6 +151,7 @@ parameters:
// 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)
}
@@ -184,6 +187,7 @@ parameters:
// 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)
}
@@ -221,6 +225,7 @@ parameters:
// 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)
@@ -262,6 +267,7 @@ parameters:
// 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)
@@ -302,6 +308,7 @@ parameters:
// 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)

View File

@@ -19,6 +19,25 @@ type MediaTypeChanges struct {
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
}
// TotalChanges returns the total number of changes between two MediaType instances.
func (m *MediaTypeChanges) TotalChanges() int {
c := m.PropertyChanges.TotalChanges()

View File

@@ -84,6 +84,7 @@ encoding:
extChanges := CompareMediaTypes(&lDoc, &rDoc)
assert.NotNil(t, extChanges)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
assert.Equal(t, v3.ExampleLabel, extChanges.Changes[0].Property)
@@ -118,6 +119,7 @@ example:
extChanges := CompareMediaTypes(&lDoc, &rDoc)
assert.NotNil(t, extChanges)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
assert.Equal(t, v3.ExampleLabel, extChanges.Changes[0].Property)
@@ -150,6 +152,7 @@ example:
extChanges := CompareMediaTypes(&lDoc, &rDoc)
assert.NotNil(t, extChanges)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
assert.Equal(t, v3.ExampleLabel, extChanges.Changes[0].Property)
@@ -182,6 +185,7 @@ example:
extChanges := CompareMediaTypes(&rDoc, &lDoc)
assert.NotNil(t, extChanges)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
assert.Equal(t, v3.ExampleLabel, extChanges.Changes[0].Property)
@@ -221,6 +225,7 @@ encoding:
extChanges := CompareMediaTypes(&lDoc, &rDoc)
assert.NotNil(t, extChanges)
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, v3.SchemaLabel, extChanges.Changes[0].Property)
@@ -260,6 +265,7 @@ encoding:
extChanges := CompareMediaTypes(&rDoc, &lDoc)
assert.NotNil(t, extChanges)
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, v3.SchemaLabel, extChanges.Changes[0].Property)
@@ -305,5 +311,6 @@ x-tea: cup`
extChanges := CompareMediaTypes(&lDoc, &rDoc)
assert.NotNil(t, extChanges)
assert.Equal(t, 5, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 5)
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
}

View File

@@ -18,6 +18,28 @@ type OAuthFlowsChanges struct {
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
}
// TotalChanges returns the number of changes made between two OAuthFlows instances.
func (o *OAuthFlowsChanges) TotalChanges() int {
c := o.PropertyChanges.TotalChanges()
@@ -137,6 +159,16 @@ type OAuthFlowChanges struct {
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
}
// TotalChanges returns the total number of changes made between two OAuthFlow objects
func (o *OAuthFlowChanges) TotalChanges() int {
c := o.PropertyChanges.TotalChanges()

View File

@@ -74,6 +74,7 @@ x-burgers: crispy`
// compare
extChanges := CompareOAuthFlow(&lDoc, &rDoc)
assert.Equal(t, 3, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 3)
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
}
@@ -109,6 +110,7 @@ x-burgers: nice`
// 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)
@@ -146,6 +148,7 @@ x-burgers: nice`
// 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)
@@ -182,6 +185,7 @@ x-burgers: nice`
// 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)
@@ -255,6 +259,7 @@ x-coke: cola`
// compare
extChanges := CompareOAuthFlows(&lDoc, &rDoc)
assert.Equal(t, 4, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 4)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
@@ -286,6 +291,7 @@ x-coke: cola`
// compare
extChanges := CompareOAuthFlows(&rDoc, &lDoc)
assert.Equal(t, 4, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 4)
assert.Equal(t, 4, extChanges.TotalBreakingChanges())
}
@@ -325,5 +331,6 @@ x-coke: cherry`
// compare
extChanges := CompareOAuthFlows(&lDoc, &rDoc)
assert.Equal(t, 5, extChanges.TotalChanges())
assert.Equal(t, 4, extChanges.TotalBreakingChanges())
assert.Len(t, extChanges.GetAllChanges(), 5)
assert.Equal(t, 4, extChanges.TotalBreakingChanges())
}

View File

@@ -30,6 +30,37 @@ type OperationChanges struct {
CallbackChanges map[string]*CallbackChanges `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
}
// GetAllChanges returns a slice of all changes made between Operation objects
func (o *OperationChanges) GetAllChanges() []*Change {
var changes []*Change
changes = append(changes, o.Changes...)
if o.ExternalDocChanges != nil {
changes = append(changes, o.ExternalDocChanges.GetAllChanges()...)
}
for k := range o.ParameterChanges {
changes = append(changes, o.ParameterChanges[k].GetAllChanges()...)
}
if o.ResponsesChanges != nil {
changes = append(changes, o.ResponsesChanges.GetAllChanges()...)
}
for k := range o.SecurityRequirementChanges {
changes = append(changes, o.SecurityRequirementChanges[k].GetAllChanges()...)
}
if o.RequestBodyChanges != nil {
changes = append(changes, o.RequestBodyChanges.GetAllChanges()...)
}
for k := range o.ServerChanges {
changes = append(changes, o.ServerChanges[k].GetAllChanges()...)
}
for k := range o.CallbackChanges {
changes = append(changes, o.CallbackChanges[k].GetAllChanges()...)
}
if o.ExtensionChanges != nil {
changes = append(changes, o.ExtensionChanges.GetAllChanges()...)
}
return changes
}
// TotalChanges returns the total number of changes made between two Swagger or OpenAPI Operation objects.
func (o *OperationChanges) TotalChanges() int {
c := o.PropertyChanges.TotalChanges()

View File

@@ -102,6 +102,7 @@ parameters:
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -152,6 +153,7 @@ parameters:
// compare.
extChanges := CompareOperations(&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)
assert.Equal(t, "parameters", extChanges.Changes[0].Property)
@@ -205,6 +207,7 @@ parameters:
// compare.
extChanges := CompareOperations(&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)
assert.Equal(t, "parameters", extChanges.Changes[0].Property)
@@ -264,6 +267,7 @@ parameters:
// compare.
extChanges := CompareOperations(&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)
}
@@ -321,6 +325,7 @@ parameters:
// compare.
extChanges := CompareOperations(&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, "jummy", extChanges.Changes[0].Original)
@@ -378,6 +383,7 @@ parameters:
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
assert.Equal(t, PropertyAdded, extChanges.Changes[1].ChangeType)
@@ -435,6 +441,7 @@ parameters:
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
assert.Equal(t, v3.TagsLabel, extChanges.Changes[0].Property)
@@ -471,6 +478,7 @@ schemes:
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 6, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 6)
assert.Equal(t, 3, extChanges.TotalBreakingChanges())
}
@@ -504,6 +512,7 @@ responses:
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, Modified, extChanges.ResponsesChanges.ResponseChanges["200"].Changes[0].ChangeType)
assert.Equal(t, Modified, extChanges.ExternalDocChanges.Changes[0].ChangeType)
@@ -545,6 +554,7 @@ responses:
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -574,6 +584,7 @@ responses:
// compare.
extChanges := CompareOperations(&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, PropertyAdded, extChanges.Changes[1].ChangeType)
@@ -605,6 +616,7 @@ responses:
// compare.
extChanges := CompareOperations(&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, PropertyRemoved, extChanges.Changes[1].ChangeType)
@@ -640,6 +652,7 @@ security:
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.SecurityRequirementChanges[0].Changes[0].ChangeType)
assert.Equal(t, "crap", extChanges.SecurityRequirementChanges[0].Changes[0].New)
@@ -676,6 +689,7 @@ security:
// compare.
extChanges := CompareOperations(&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.SecurityRequirementChanges[0].Changes[0].ChangeType)
assert.Equal(t, "crap", extChanges.SecurityRequirementChanges[0].Changes[0].Original)
@@ -714,6 +728,7 @@ security:
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
assert.Equal(t, "thongs", extChanges.Changes[0].New)
@@ -752,6 +767,7 @@ security:
// compare.
extChanges := CompareOperations(&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, "thongs", extChanges.Changes[0].Original)
@@ -831,6 +847,7 @@ func TestCompareOperations_V3_ModifyParam(t *testing.T) {
// compare.
extChanges := CompareOperations(&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.ParameterChanges[0].Changes[0].ChangeType)
}
@@ -864,6 +881,7 @@ func TestCompareOperations_V3_AddParam(t *testing.T) {
// compare.
extChanges := CompareOperations(&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)
}
@@ -897,6 +915,7 @@ func TestCompareOperations_V3_RemoveParam(t *testing.T) {
// compare.
extChanges := CompareOperations(&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)
}
@@ -926,6 +945,7 @@ parameters:
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
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)
}
@@ -955,6 +975,7 @@ parameters:
// compare.
extChanges := CompareOperations(&rDoc, &lDoc)
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)
}
@@ -985,6 +1006,7 @@ func TestCompareOperations_V3_ModifyServers(t *testing.T) {
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, PropertyAdded, extChanges.ServerChanges[0].Changes[0].ChangeType)
}
@@ -1018,6 +1040,7 @@ func TestCompareOperations_V3_ModifyCallback(t *testing.T) {
// compare.
extChanges := CompareOperations(&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.
CallbackChanges["myCallback"].
@@ -1058,6 +1081,7 @@ func TestCompareOperations_V3_AddCallback(t *testing.T) {
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
}
@@ -1092,6 +1116,7 @@ callbacks:
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
}
@@ -1126,6 +1151,7 @@ callbacks:
// compare.
extChanges := CompareOperations(&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)
}
@@ -1163,6 +1189,7 @@ func TestCompareOperations_V3_RemoveCallback(t *testing.T) {
// compare.
extChanges := CompareOperations(&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)
}
@@ -1191,6 +1218,7 @@ func TestCompareOperations_V3_AddServer(t *testing.T) {
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.ServerChanges[0].Changes[0].ChangeType)
}
@@ -1219,6 +1247,7 @@ func TestCompareOperations_V3_RemoveServer(t *testing.T) {
// compare.
extChanges := CompareOperations(&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.ServerChanges[0].Changes[0].ChangeType)
}
@@ -1247,6 +1276,7 @@ servers:
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, PropertyAdded, extChanges.ServerChanges[0].Changes[0].ChangeType)
}
@@ -1275,6 +1305,7 @@ servers:
// compare.
extChanges := CompareOperations(&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.ServerChanges[0].Changes[0].ChangeType)
}
@@ -1307,6 +1338,7 @@ security:
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.SecurityRequirementChanges[0].Changes[0].ChangeType)
}
@@ -1335,6 +1367,7 @@ security:
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Empty(t, extChanges.SecurityRequirementChanges)
}
@@ -1363,6 +1396,7 @@ security: []`
// compare.
extChanges := CompareOperations(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
assert.Empty(t, extChanges.SecurityRequirementChanges)
}
@@ -1390,6 +1424,7 @@ func TestCompareOperations_V3_ModifyRequestBody(t *testing.T) {
// compare.
extChanges := CompareOperations(&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.RequestBodyChanges.Changes[0].ChangeType)
}
@@ -1417,6 +1452,7 @@ requestBody:
// compare.
extChanges := CompareOperations(&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)
}
@@ -1442,6 +1478,7 @@ func TestCompareOperations_V3_ModifyExtension(t *testing.T) {
// compare.
extChanges := CompareOperations(&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)
}
@@ -1469,6 +1506,7 @@ requestBody:
// compare.
extChanges := CompareOperations(&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)
}

View File

@@ -26,6 +26,28 @@ type ParameterChanges struct {
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
}
// TotalChanges returns a count of everything that changed
func (p *ParameterChanges) TotalChanges() int {
c := p.PropertyChanges.TotalChanges()

View File

@@ -78,6 +78,7 @@ func TestCompareParameters_V3_Schema(t *testing.T) {
// compare.
extChanges := CompareParameters(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, 1, extChanges.SchemaChanges.TotalChanges())
@@ -105,6 +106,7 @@ schema:
// compare.
extChanges := CompareParameters(&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)
@@ -132,6 +134,7 @@ schema:
// compare.
extChanges := CompareParameters(&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)
@@ -157,6 +160,7 @@ func TestCompareParameters_V3_Extensions(t *testing.T) {
// compare.
extChanges := CompareParameters(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, 1, extChanges.ExtensionChanges.TotalChanges())
@@ -183,6 +187,7 @@ func TestCompareParameters_V3_ExampleChange(t *testing.T) {
// compare.
extChanges := CompareParameters(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
@@ -229,6 +234,7 @@ example: a string`
// compare
extChanges := CompareParameters(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
}
@@ -254,6 +260,7 @@ example: a string`
// compare
extChanges := CompareParameters(&rDoc, &lDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
}
@@ -282,6 +289,7 @@ func TestCompareParameters_V3_ExamplesChanged(t *testing.T) {
// compare
extChanges := CompareParameters(&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.ExamplesChanges["anExample"].Changes[0].ChangeType)
}
@@ -313,6 +321,7 @@ func TestCompareParameters_V3_ExamplesAdded(t *testing.T) {
// compare
extChanges := CompareParameters(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
}
@@ -344,6 +353,7 @@ func TestCompareParameters_V3_ExamplesRemoved(t *testing.T) {
// compare
extChanges := CompareParameters(&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)
}
@@ -375,6 +385,7 @@ func TestCompareParameters_V3_ContentChanged(t *testing.T) {
// compare
extChanges := CompareParameters(&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.ContentChanges["application/json"].SchemaChanges.Changes[0].ChangeType)
@@ -410,6 +421,7 @@ func TestCompareParameters_V3_ContentAdded(t *testing.T) {
// compare
extChanges := CompareParameters(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
}
@@ -434,6 +446,7 @@ func TestCompareParameters_V2_DefaultChange(t *testing.T) {
// compare.
extChanges := CompareParameters(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -458,6 +471,7 @@ default: wat?`
// compare.
extChanges := CompareParameters(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -483,6 +497,7 @@ func TestCompareParameters_V2_EnumChange(t *testing.T) {
// compare.
extChanges := CompareParameters(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -533,6 +548,7 @@ example: a string`
// compare
extChanges := CompareParameters(&rDoc, &lDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
}
@@ -603,6 +619,7 @@ func TestCompareParameters_V2_ItemsChange(t *testing.T) {
// compare.
extChanges := CompareParameters(&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.ItemsChanges.Changes[0].ChangeType)
@@ -630,6 +647,7 @@ items:
// compare.
extChanges := CompareParameters(&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)
}
@@ -656,6 +674,7 @@ items:
// compare.
extChanges := CompareParameters(&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)
}
@@ -680,6 +699,7 @@ func TestCompareParameters_V2_Extensions(t *testing.T) {
// compare.
extChanges := CompareParameters(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, 1, extChanges.ExtensionChanges.TotalChanges())
}

View File

@@ -27,6 +27,46 @@ type PathItemChanges struct {
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
}
// GetAllChanges returns a slice of all changes made between PathItem objects
func (p *PathItemChanges) GetAllChanges() []*Change {
var changes []*Change
changes = append(changes, p.Changes...)
if p.GetChanges != nil {
changes = append(changes, p.GetChanges.GetAllChanges()...)
}
if p.PutChanges != nil {
changes = append(changes, p.PutChanges.GetAllChanges()...)
}
if p.PostChanges != nil {
changes = append(changes, p.PostChanges.GetAllChanges()...)
}
if p.DeleteChanges != nil {
changes = append(changes, p.DeleteChanges.GetAllChanges()...)
}
if p.OptionsChanges != nil {
changes = append(changes, p.OptionsChanges.GetAllChanges()...)
}
if p.HeadChanges != nil {
changes = append(changes, p.HeadChanges.GetAllChanges()...)
}
if p.PatchChanges != nil {
changes = append(changes, p.PatchChanges.GetAllChanges()...)
}
if p.TraceChanges != nil {
changes = append(changes, p.TraceChanges.GetAllChanges()...)
}
for i := range p.ServerChanges {
changes = append(changes, p.ServerChanges[i].GetAllChanges()...)
}
for i := range p.ParameterChanges {
changes = append(changes, p.ParameterChanges[i].GetAllChanges()...)
}
if p.ExtensionChanges != nil {
changes = append(changes, p.ExtensionChanges.GetAllChanges()...)
}
return changes
}
// TotalChanges returns the total number of changes found between two Swagger or OpenAPI PathItems
func (p *PathItemChanges) TotalChanges() int {
c := p.PropertyChanges.TotalChanges()

View File

@@ -105,6 +105,7 @@ x-thing: ding-a-ling`
// compare.
extChanges := ComparePathItems(&lDoc, &rDoc)
assert.Equal(t, 8, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 8)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}

View File

@@ -18,6 +18,19 @@ type PathsChanges struct {
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
}
// TotalChanges returns the total number of changes between two Swagger or OpenAPI Paths Objects
func (p *PathsChanges) TotalChanges() int {
c := p.PropertyChanges.TotalChanges()

View File

@@ -84,6 +84,7 @@ x-windows: washed
// compare.
extChanges := ComparePaths(&lDoc, &rDoc)
assert.Equal(t, 4, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 4)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
@@ -123,6 +124,7 @@ x-windows: dirty
// compare.
extChanges := ComparePaths(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
assert.Equal(t, "/crispy/chips", extChanges.Changes[0].New)
@@ -164,6 +166,7 @@ x-windows: dirty
// compare.
extChanges := ComparePaths(&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, "/crispy/chips", extChanges.Changes[0].Original)
@@ -240,6 +243,7 @@ x-windows: washed
// compare.
extChanges := ComparePaths(&lDoc, &rDoc)
assert.Equal(t, 4, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 4)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
@@ -286,6 +290,7 @@ x-windows: dirty`
// compare.
extChanges := ComparePaths(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
assert.Equal(t, "/mushy/peas", extChanges.Changes[0].New)
@@ -334,6 +339,7 @@ x-windows: dirty`
// compare.
extChanges := ComparePaths(&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, "/mushy/peas", extChanges.Changes[0].Original)

View File

@@ -15,6 +15,19 @@ type RequestBodyChanges struct {
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
}
// TotalChanges returns the total number of changes found between two OpenAPI RequestBody objects
func (rb *RequestBodyChanges) TotalChanges() int {
c := rb.PropertyChanges.TotalChanges()

View File

@@ -78,5 +78,6 @@ content:
extChanges := CompareRequestBodies(&lDoc, &rDoc)
assert.Equal(t, 4, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 4)
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
}

View File

@@ -26,6 +26,34 @@ type ResponseChanges struct {
ServerChanges *ServerChanges `json:"server,omitempty" yaml:"server,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()...)
}
if r.ServerChanges != nil {
changes = append(changes, r.ServerChanges.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()
@@ -38,6 +66,9 @@ func (r *ResponseChanges) TotalChanges() int {
if r.ExamplesChanges != nil {
c += r.ExamplesChanges.TotalChanges()
}
if r.ServerChanges != nil {
c += r.ServerChanges.TotalChanges()
}
for k := range r.HeadersChanges {
c += r.HeadersChanges[k].TotalChanges()
}
@@ -57,6 +88,9 @@ func (r *ResponseChanges) TotalBreakingChanges() int {
if r.SchemaChanges != nil {
c += r.SchemaChanges.TotalBreakingChanges()
}
if r.ServerChanges != nil {
c += r.ServerChanges.TotalBreakingChanges()
}
for k := range r.HeadersChanges {
c += r.HeadersChanges[k].TotalBreakingChanges()
}

View File

@@ -77,6 +77,7 @@ x-toot: poot`
extChanges := CompareResponse(&lDoc, &rDoc)
assert.Equal(t, 5, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 5)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -110,6 +111,7 @@ examples:
extChanges := CompareResponse(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -143,6 +145,7 @@ examples:
extChanges := CompareResponse(&rDoc, &lDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -223,5 +226,6 @@ x-toot: pooty`
extChanges := CompareResponse(&lDoc, &rDoc)
assert.Equal(t, 5, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 5)
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
}

View File

@@ -18,6 +18,22 @@ type ResponsesChanges struct {
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
}
// TotalChanges returns the total number of changes found between two Swagger or OpenAPI Responses objects
func (r *ResponsesChanges) TotalChanges() int {
c := r.PropertyChanges.TotalChanges()

View File

@@ -81,6 +81,7 @@ x-ting: tang`
extChanges := CompareResponses(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
assert.Equal(t, Modified, extChanges.ResponseChanges["404"].SchemaChanges.Changes[0].ChangeType)
assert.Equal(t, Modified, extChanges.ResponseChanges["200"].SchemaChanges.Changes[0].ChangeType)
@@ -121,6 +122,7 @@ x-apple: pie`
extChanges := CompareResponses(&rDoc, &lDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.ResponseChanges["200"].Changes[0].ChangeType)
}
@@ -156,6 +158,7 @@ func TestCompareResponses_V2_RemoveSchema(t *testing.T) {
extChanges := CompareResponses(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectRemoved, extChanges.ResponseChanges["200"].Changes[0].ChangeType)
}
@@ -189,6 +192,7 @@ default:
extChanges := CompareResponses(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
}
@@ -222,6 +226,7 @@ default:
extChanges := CompareResponses(&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)
}
@@ -259,6 +264,7 @@ default:
extChanges := CompareResponses(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -322,6 +328,7 @@ x-coffee: yum
extChanges := CompareResponses(&lDoc, &rDoc)
assert.Equal(t, 4, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 4)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
@@ -355,6 +362,7 @@ default:
extChanges := CompareResponses(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, v3.DefaultLabel, extChanges.Changes[0].Property)
}
@@ -389,6 +397,7 @@ default:
extChanges := CompareResponses(&rDoc, &lDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
assert.Equal(t, v3.DefaultLabel, extChanges.Changes[0].Property)
}
@@ -425,6 +434,7 @@ default:
extChanges := CompareResponses(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, v3.DescriptionLabel, extChanges.DefaultChanges.Changes[0].Property)
}
@@ -457,5 +467,6 @@ func TestCompareResponses_V3_AddRemoveMediaType(t *testing.T) {
extChanges := CompareResponses(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}

View File

@@ -45,6 +45,94 @@ type SchemaChanges struct {
PatternPropertiesChanges map[string]*SchemaChanges `json:"patternProperties,omitempty" yaml:"patternProperties,omitempty"`
}
// GetAllChanges returns a slice of all changes made between Responses objects
func (s *SchemaChanges) GetAllChanges() []*Change {
var changes []*Change
changes = append(changes, s.Changes...)
if s.DiscriminatorChanges != nil {
changes = append(changes, s.DiscriminatorChanges.GetAllChanges()...)
}
if len(s.AllOfChanges) > 0 {
for n := range s.AllOfChanges {
if s.AllOfChanges[n] != nil {
changes = append(changes, s.AllOfChanges[n].GetAllChanges()...)
}
}
}
if len(s.AnyOfChanges) > 0 {
for n := range s.AnyOfChanges {
if s.AnyOfChanges[n] != nil {
changes = append(changes, s.AnyOfChanges[n].GetAllChanges()...)
}
}
}
if len(s.OneOfChanges) > 0 {
for n := range s.OneOfChanges {
if s.OneOfChanges[n] != nil {
changes = append(changes, s.OneOfChanges[n].GetAllChanges()...)
}
}
}
if s.NotChanges != nil {
changes = append(changes, s.NotChanges.GetAllChanges()...)
}
if s.ItemsChanges != nil {
changes = append(changes, s.ItemsChanges.GetAllChanges()...)
}
if s.IfChanges != nil {
changes = append(changes, s.IfChanges.GetAllChanges()...)
}
if s.ElseChanges != nil {
changes = append(changes, s.ElseChanges.GetAllChanges()...)
}
if s.ThenChanges != nil {
changes = append(changes, s.ThenChanges.GetAllChanges()...)
}
if s.PropertyNamesChanges != nil {
changes = append(changes, s.PropertyNamesChanges.GetAllChanges()...)
}
if s.ContainsChanges != nil {
changes = append(changes, s.ContainsChanges.GetAllChanges()...)
}
if s.UnevaluatedItemsChanges != nil {
changes = append(changes, s.UnevaluatedItemsChanges.GetAllChanges()...)
}
if s.UnevaluatedPropertiesChanges != nil {
changes = append(changes, s.UnevaluatedPropertiesChanges.GetAllChanges()...)
}
if s.SchemaPropertyChanges != nil {
for n := range s.SchemaPropertyChanges {
if s.SchemaPropertyChanges[n] != nil {
changes = append(changes, s.SchemaPropertyChanges[n].GetAllChanges()...)
}
}
}
if s.DependentSchemasChanges != nil {
for n := range s.DependentSchemasChanges {
if s.DependentSchemasChanges[n] != nil {
changes = append(changes, s.DependentSchemasChanges[n].GetAllChanges()...)
}
}
}
if s.PatternPropertiesChanges != nil {
for n := range s.PatternPropertiesChanges {
if s.PatternPropertiesChanges[n] != nil {
changes = append(changes, s.PatternPropertiesChanges[n].GetAllChanges()...)
}
}
}
if s.ExternalDocChanges != nil {
changes = append(changes, s.ExternalDocChanges.GetAllChanges()...)
}
if s.XMLChanges != nil {
changes = append(changes, s.XMLChanges.GetAllChanges()...)
}
if s.ExtensionChanges != nil {
changes = append(changes, s.ExtensionChanges.GetAllChanges()...)
}
return changes
}
// TotalChanges returns a count of the total number of changes made to this schema and all sub-schemas
func (s *SchemaChanges) TotalChanges() int {
t := s.PropertyChanges.TotalChanges()
@@ -58,7 +146,9 @@ func (s *SchemaChanges) TotalChanges() int {
}
if len(s.AnyOfChanges) > 0 {
for n := range s.AnyOfChanges {
t += s.AnyOfChanges[n].TotalChanges()
if s.AnyOfChanges[n] != nil {
t += s.AnyOfChanges[n].TotalChanges()
}
}
}
if len(s.OneOfChanges) > 0 {
@@ -95,7 +185,9 @@ func (s *SchemaChanges) TotalChanges() int {
}
if s.SchemaPropertyChanges != nil {
for n := range s.SchemaPropertyChanges {
t += s.SchemaPropertyChanges[n].TotalChanges()
if s.SchemaPropertyChanges[n] != nil {
t += s.SchemaPropertyChanges[n].TotalChanges()
}
}
}
if s.DependentSchemasChanges != nil {
@@ -302,7 +394,10 @@ func CompareSchemas(l, r *base.SchemaProxy) *SchemaChanges {
} else {
sc.PropertyChanges = NewPropertyChanges(nil)
}
return sc
if sc.TotalChanges() > 0 {
return sc
}
return nil
}
func checkSchemaXML(lSchema *base.Schema, rSchema *base.Schema, changes *[]*Change, sc *SchemaChanges) {

View File

@@ -43,6 +43,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 0, changes.TotalBreakingChanges())
assert.Equal(t, Modified, changes.Changes[0].ChangeType)
assert.Equal(t, "an OK message Changed", changes.Changes[0].New)
@@ -71,6 +72,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.Changes, 1)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, PropertyAdded, changes.Changes[0].ChangeType)
assert.Equal(t, "a thing", changes.Changes[0].New)
assert.Equal(t, v3.DescriptionLabel, changes.Changes[0].Property)
@@ -99,6 +101,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.Changes, 1)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, PropertyRemoved, changes.Changes[0].ChangeType)
assert.Equal(t, "a thing", changes.Changes[0].Original)
assert.Equal(t, v3.DescriptionLabel, changes.Changes[0].Property)
@@ -125,6 +128,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.Changes, 1)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, ObjectRemoved, changes.Changes[0].ChangeType)
}
@@ -149,6 +153,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.Changes, 1)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, ObjectAdded, changes.Changes[0].ChangeType)
}
@@ -238,6 +243,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.Changes, 1)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, Modified, changes.Changes[0].ChangeType)
assert.Equal(t, "#/components/schemas/Yo", changes.Changes[0].New)
}
@@ -268,6 +274,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.Changes, 1)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, Modified, changes.Changes[0].ChangeType)
assert.Equal(t, v3.RefLabel, changes.Changes[0].Property)
assert.Equal(t, "#/components/schemas/Yo", changes.Changes[0].Original)
@@ -300,6 +307,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.Changes, 1)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, Modified, changes.Changes[0].ChangeType)
assert.Equal(t, v3.RefLabel, changes.Changes[0].Property)
assert.Equal(t, "#/components/schemas/Yo", changes.Changes[0].New)
@@ -389,6 +397,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.Changes, 1)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, PropertyAdded, changes.Changes[0].ChangeType)
assert.Equal(t, "two", changes.Changes[0].New)
assert.Equal(t, v3.RequiredLabel, changes.Changes[0].Property)
@@ -419,6 +428,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.Changes, 1)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, PropertyRemoved, changes.Changes[0].ChangeType)
assert.Equal(t, "two", changes.Changes[0].Original)
assert.Equal(t, v3.RequiredLabel, changes.Changes[0].Property)
@@ -446,6 +456,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.Changes, 1)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, PropertyAdded, changes.Changes[0].ChangeType)
assert.Equal(t, "d", changes.Changes[0].New)
assert.Equal(t, v3.EnumLabel, changes.Changes[0].Property)
@@ -473,6 +484,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.Changes, 1)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, PropertyRemoved, changes.Changes[0].ChangeType)
assert.Equal(t, "d", changes.Changes[0].Original)
assert.Equal(t, v3.EnumLabel, changes.Changes[0].Property)
@@ -506,6 +518,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.Changes, 1)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, ObjectAdded, changes.Changes[0].ChangeType)
assert.Equal(t, "propB", changes.Changes[0].New)
assert.Equal(t, v3.PropertiesLabel, changes.Changes[0].Property)
@@ -539,6 +552,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.Changes, 1)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, ObjectRemoved, changes.Changes[0].ChangeType)
assert.Equal(t, "propB", changes.Changes[0].Original)
assert.Equal(t, v3.PropertiesLabel, changes.Changes[0].Property)
@@ -568,6 +582,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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, 1, changes.IfChanges.PropertyChanges.TotalChanges())
}
@@ -596,6 +611,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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.IfLabel, changes.Changes[0].Property)
}
@@ -624,6 +640,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
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.IfLabel, changes.Changes[0].Property)
}
@@ -652,6 +669,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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, 1, changes.ElseChanges.PropertyChanges.TotalChanges())
}
@@ -680,6 +698,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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.ElseLabel, changes.Changes[0].Property)
}
@@ -708,6 +727,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
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.ElseLabel, changes.Changes[0].Property)
}
@@ -736,6 +756,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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, 1, changes.ThenChanges.PropertyChanges.TotalChanges())
}
@@ -764,6 +785,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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.ThenLabel, changes.Changes[0].Property)
}
@@ -792,6 +814,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
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.ThenLabel, changes.Changes[0].Property)
}
@@ -822,6 +845,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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, 1, changes.DependentSchemasChanges["schemaOne"].PropertyChanges.TotalChanges())
}
@@ -852,6 +876,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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, 1, changes.PatternPropertiesChanges["schemaOne"].PropertyChanges.TotalChanges())
}
@@ -880,6 +905,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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, 1, changes.PropertyNamesChanges.PropertyChanges.TotalChanges())
}
@@ -908,6 +934,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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.PropertyNamesLabel, changes.Changes[0].Property)
}
@@ -936,6 +963,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
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.PropertyNamesLabel, changes.Changes[0].Property)
}
@@ -964,6 +992,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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, 1, changes.ContainsChanges.PropertyChanges.TotalChanges())
}
@@ -992,6 +1021,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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.ContainsLabel, changes.Changes[0].Property)
}
@@ -1020,6 +1050,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
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.ContainsLabel, changes.Changes[0].Property)
}
@@ -1048,6 +1079,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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, 1, changes.UnevaluatedPropertiesChanges.PropertyChanges.TotalChanges())
}
@@ -1076,6 +1108,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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.UnevaluatedPropertiesLabel, changes.Changes[0].Property)
}
@@ -1104,6 +1137,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
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.UnevaluatedPropertiesLabel, changes.Changes[0].Property)
}
@@ -1132,6 +1166,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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, 1, changes.UnevaluatedItemsChanges.PropertyChanges.TotalChanges())
}
@@ -1160,6 +1195,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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.UnevaluatedItemsLabel, changes.Changes[0].Property)
}
@@ -1188,6 +1224,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
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.UnevaluatedItemsLabel, changes.Changes[0].Property)
}
@@ -1213,6 +1250,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 1, changes.TotalChanges())
assert.Equal(t, 1, changes.TotalBreakingChanges())
}
@@ -1239,6 +1277,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 1, changes.TotalChanges())
assert.Equal(t, 1, changes.TotalBreakingChanges())
}
@@ -1265,6 +1304,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 1, changes.TotalChanges())
assert.Equal(t, 1, changes.TotalBreakingChanges())
}
@@ -1292,6 +1332,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 1, changes.TotalChanges())
assert.Equal(t, 1, changes.TotalBreakingChanges())
}
@@ -1320,6 +1361,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 1, changes.TotalBreakingChanges())
}
@@ -1349,6 +1391,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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, Modified, changes.SchemaPropertyChanges["propA"].Changes[0].ChangeType)
assert.Equal(t, "string", changes.SchemaPropertyChanges["propA"].Changes[0].New)
@@ -1381,6 +1424,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 2, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 2)
assert.Equal(t, 1, changes.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, changes.Changes[0].ChangeType)
assert.Equal(t, "propN", changes.Changes[0].New)
@@ -1415,6 +1459,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 2, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 2)
assert.Equal(t, 1, changes.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, changes.Changes[0].ChangeType)
assert.Equal(t, v3.AnyOfLabel, changes.Changes[0].Property)
@@ -1448,6 +1493,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
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, ObjectRemoved, changes.Changes[0].ChangeType)
assert.Equal(t, v3.AnyOfLabel, changes.Changes[0].Property)
@@ -1480,6 +1526,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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, Modified, changes.AnyOfChanges[0].Changes[0].ChangeType)
assert.Equal(t, "string", changes.AnyOfChanges[0].Changes[0].New)
@@ -1512,6 +1559,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 2, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 2)
assert.Equal(t, 1, changes.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, changes.Changes[0].ChangeType)
assert.Equal(t, v3.OneOfLabel, changes.Changes[0].Property)
@@ -1545,6 +1593,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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, ObjectAdded, changes.Changes[0].ChangeType)
assert.Equal(t, v3.AllOfLabel, changes.Changes[0].Property)
@@ -1579,6 +1628,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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.ItemsChanges.Changes[0].Property)
assert.Equal(t, Modified, changes.ItemsChanges.Changes[0].ChangeType)
@@ -1612,6 +1662,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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.ItemsChanges.Changes[0].Property)
assert.Equal(t, Modified, changes.ItemsChanges.Changes[0].ChangeType)
@@ -1645,6 +1696,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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.NotChanges.Changes[0].Property)
assert.Equal(t, Modified, changes.NotChanges.Changes[0].ChangeType)
@@ -1678,6 +1730,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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.PropertyNameLabel, changes.DiscriminatorChanges.Changes[0].Property)
assert.Equal(t, Modified, changes.DiscriminatorChanges.Changes[0].ChangeType)
@@ -1709,6 +1762,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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.DiscriminatorLabel, changes.Changes[0].Property)
assert.Equal(t, ObjectAdded, changes.Changes[0].ChangeType)
@@ -1741,6 +1795,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
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.DiscriminatorLabel, changes.Changes[0].Property)
assert.Equal(t, ObjectRemoved, changes.Changes[0].ChangeType)
@@ -1775,6 +1830,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 0, changes.TotalBreakingChanges())
assert.Equal(t, v3.URLLabel, changes.ExternalDocChanges.Changes[0].Property)
assert.Equal(t, Modified, changes.ExternalDocChanges.Changes[0].ChangeType)
@@ -1806,6 +1862,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 0, changes.TotalBreakingChanges())
assert.Equal(t, v3.ExternalDocsLabel, changes.Changes[0].Property)
assert.Equal(t, ObjectAdded, changes.Changes[0].ChangeType)
@@ -1838,6 +1895,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 0, changes.TotalBreakingChanges())
assert.Equal(t, v3.ExternalDocsLabel, changes.Changes[0].Property)
assert.Equal(t, ObjectRemoved, changes.Changes[0].ChangeType)
@@ -1869,6 +1927,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 0, changes.TotalBreakingChanges())
assert.Equal(t, "x-melody", changes.ExtensionChanges.Changes[0].Property)
assert.Equal(t, ObjectAdded, changes.ExtensionChanges.Changes[0].ChangeType)
@@ -1927,6 +1986,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 0, changes.TotalBreakingChanges())
assert.Equal(t, v3.ExampleLabel, changes.Changes[0].Property)
assert.Equal(t, PropertyAdded, changes.Changes[0].ChangeType)
@@ -1956,6 +2016,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 0, changes.TotalBreakingChanges())
assert.Equal(t, v3.ExampleLabel, changes.Changes[0].Property)
assert.Equal(t, PropertyRemoved, changes.Changes[0].ChangeType)
@@ -1988,6 +2049,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 0, changes.TotalBreakingChanges())
assert.Equal(t, v3.ExamplesLabel, changes.Changes[0].Property)
assert.Equal(t, Modified, changes.Changes[0].ChangeType)
@@ -2019,6 +2081,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 0, changes.TotalBreakingChanges())
assert.Equal(t, v3.ExamplesLabel, changes.Changes[0].Property)
assert.Equal(t, ObjectAdded, changes.Changes[0].ChangeType)
@@ -2052,6 +2115,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 2, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 2)
assert.Equal(t, 0, changes.TotalBreakingChanges())
assert.Equal(t, v3.ExamplesLabel, changes.Changes[0].Property)
assert.Equal(t, Modified, changes.Changes[0].ChangeType)
@@ -2085,6 +2149,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 0, changes.TotalBreakingChanges())
assert.Equal(t, v3.ExamplesLabel, changes.Changes[0].Property)
assert.Equal(t, ObjectRemoved, changes.Changes[0].ChangeType)
@@ -2118,6 +2183,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
assert.NotNil(t, changes)
assert.Equal(t, 2, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 2)
assert.Equal(t, 0, changes.TotalBreakingChanges())
assert.Equal(t, v3.ExamplesLabel, changes.Changes[0].Property)
assert.Equal(t, Modified, changes.Changes[0].ChangeType)
@@ -2151,6 +2217,7 @@ components:
changes := CompareSchemas(lSchemaProxy, rSchemaProxy)
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.NameLabel, changes.XMLChanges.Changes[0].Property)
assert.Equal(t, Modified, changes.XMLChanges.Changes[0].ChangeType)
@@ -2210,6 +2277,7 @@ components:
changes := CompareSchemas(rSchemaProxy, lSchemaProxy)
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.XMLLabel, changes.Changes[0].Property)
assert.Equal(t, ObjectRemoved, changes.Changes[0].ChangeType)
@@ -2252,6 +2320,7 @@ components:
changes := CompareDocuments(leftDoc, rightDoc)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 1, changes.TotalBreakingChanges())
}
@@ -2281,6 +2350,7 @@ components:
changes := CompareDocuments(leftDoc, rightDoc)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 0, changes.TotalBreakingChanges())
}
@@ -2314,6 +2384,7 @@ components:
changes := CompareDocuments(leftDoc, rightDoc)
assert.NotNil(t, changes)
assert.Equal(t, 1, changes.TotalChanges())
assert.Len(t, changes.GetAllChanges(), 1)
assert.Equal(t, 1, changes.TotalBreakingChanges())
}

View File

@@ -15,6 +15,16 @@ type ScopesChanges struct {
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
}
// TotalChanges returns the total changes found between two Swagger Scopes objects.
func (s *ScopesChanges) TotalChanges() int {
c := s.PropertyChanges.TotalChanges()

View File

@@ -61,6 +61,7 @@ x-nugget: chicken`
// compare.
extChanges := CompareScopes(&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, "pie", extChanges.Changes[0].New)
@@ -89,6 +90,7 @@ x-nugget: chicken`
// compare.
extChanges := CompareScopes(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
assert.Equal(t, "sky", extChanges.Changes[0].New)
@@ -118,6 +120,7 @@ x-nugget: soup`
// compare.
extChanges := CompareScopes(&rDoc, &lDoc)
assert.Equal(t, 2, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 2)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
assert.Equal(t, "sky", extChanges.Changes[0].Original)

View File

@@ -15,6 +15,11 @@ type SecurityRequirementChanges struct {
*PropertyChanges
}
// GetAllChanges returns a slice of all changes made between SecurityRequirement objects
func (s *SecurityRequirementChanges) GetAllChanges() []*Change {
return s.Changes
}
// TotalChanges returns the total number of changes between two SecurityRequirement Objects.
func (s *SecurityRequirementChanges) TotalChanges() int {
return s.PropertyChanges.TotalChanges()

View File

@@ -69,6 +69,7 @@ biscuit:
// compare
extChanges := CompareSecurityRequirement(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
assert.Equal(t, "biscuit", extChanges.Changes[0].NewObject)
@@ -101,6 +102,7 @@ biscuit:
// compare
extChanges := CompareSecurityRequirement(&rDoc, &lDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
}
@@ -133,6 +135,7 @@ milk:
// compare
extChanges := CompareSecurityRequirement(&lDoc, &rDoc)
assert.Equal(t, 4, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 4)
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
assert.Equal(t, ObjectRemoved, extChanges.Changes[1].ChangeType)

View File

@@ -22,6 +22,22 @@ type SecuritySchemeChanges struct {
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
}
// TotalChanges represents total changes found between two Swagger or OpenAPI SecurityScheme instances.
func (ss *SecuritySchemeChanges) TotalChanges() int {
c := ss.PropertyChanges.TotalChanges()

View File

@@ -72,6 +72,7 @@ x-beer: very tasty`
// compare
extChanges := CompareSecuritySchemes(&lDoc, &rDoc)
assert.Equal(t, 4, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 4)
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
assert.Equal(t, Modified, extChanges.Changes[1].ChangeType)
@@ -103,6 +104,7 @@ scopes:
// compare
extChanges := CompareSecuritySchemes(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
assert.Equal(t, v3.ScopesLabel, extChanges.Changes[0].Property)
@@ -132,6 +134,7 @@ scopes:
// compare
extChanges := CompareSecuritySchemes(&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, v3.ScopesLabel, extChanges.Changes[0].Property)
@@ -161,6 +164,7 @@ func TestCompareSecuritySchemes_v2_ModifyScope(t *testing.T) {
// compare
extChanges := CompareSecuritySchemes(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.ScopesChanges.Changes[0].ChangeType)
assert.Equal(t, v3.ScopesLabel, extChanges.ScopesChanges.Changes[0].Property)
@@ -226,6 +230,7 @@ x-beer: cool`
// compare
extChanges := CompareSecuritySchemes(&lDoc, &rDoc)
assert.Equal(t, 5, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 5)
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
assert.Equal(t, Modified, extChanges.Changes[0].ChangeType)
assert.Equal(t, Modified, extChanges.Changes[1].ChangeType)
@@ -258,6 +263,7 @@ flows:
// compare
extChanges := CompareSecuritySchemes(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
}
@@ -286,6 +292,7 @@ flows:
// compare
extChanges := CompareSecuritySchemes(&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)
}
@@ -317,6 +324,7 @@ flows:
// compare
extChanges := CompareSecuritySchemes(&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.OAuthFlowChanges.ImplicitChanges.Changes[0].ChangeType)
}

View File

@@ -14,6 +14,16 @@ type ServerChanges struct {
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
}
// TotalChanges returns total changes found between two OpenAPI Server Objects
func (s *ServerChanges) TotalChanges() int {
c := s.PropertyChanges.TotalChanges()

View File

@@ -83,6 +83,7 @@ variables:
// compare.
extChanges := CompareServers(&lDoc, &rDoc)
assert.Equal(t, 3, extChanges.TotalChanges())
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
}
@@ -120,6 +121,7 @@ variables:
// 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)
@@ -159,6 +161,7 @@ variables:
// 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)

View File

@@ -13,6 +13,11 @@ type ServerVariableChanges struct {
*PropertyChanges
}
// GetAllChanges returns a slice of all changes made between SecurityRequirement objects
func (s *ServerVariableChanges) GetAllChanges() []*Change {
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 {

View File

@@ -67,6 +67,7 @@ enum:
// compare.
extChanges := CompareServerVariables(&lDoc, &rDoc)
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)
@@ -100,6 +101,7 @@ enum:
// compare.
extChanges := CompareServerVariables(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges())
assert.Len(t, extChanges.GetAllChanges(), 1)
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
}
@@ -129,6 +131,7 @@ enum:
// compare.
extChanges := CompareServerVariables(&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)
}
@@ -159,6 +162,7 @@ enum:
// compare.
extChanges := CompareServerVariables(&rDoc, &lDoc)
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)
}

View File

@@ -16,6 +16,19 @@ type TagChanges struct {
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
}
// TotalChanges returns a count of everything that changed within tags.
func (t *TagChanges) TotalChanges() int {
c := t.PropertyChanges.TotalChanges()

View File

@@ -44,6 +44,7 @@ tags:
assert.Len(t, changes[0].ExternalDocs.Changes, 2)
assert.Len(t, changes[0].ExtensionChanges.Changes, 1)
assert.Equal(t, 4, changes[0].TotalChanges())
assert.Len(t, changes[0].GetAllChanges(), 4)
descChange := changes[0].Changes[0]
assert.Equal(t, "a lovelier tag description", descChange.New)
@@ -86,6 +87,7 @@ tags:
// evaluate.
assert.Len(t, changes[0].Changes, 1)
assert.Equal(t, 1, changes[0].TotalChanges())
assert.Len(t, changes[0].GetAllChanges(), 1)
descChange := changes[0].Changes[0]
assert.Equal(t, ObjectAdded, descChange.ChangeType)
@@ -119,6 +121,7 @@ tags:
// evaluate.
assert.Len(t, changes, 2)
assert.Equal(t, 1, changes[0].TotalChanges())
assert.Len(t, changes[0].GetAllChanges(), 1)
assert.Equal(t, 1, changes[1].TotalChanges())
assert.Equal(t, 1, changes[0].TotalBreakingChanges())
}
@@ -222,6 +225,7 @@ tags:
// evaluate.
assert.Len(t, changes[0].Changes, 1)
assert.Equal(t, 1, changes[0].TotalChanges())
assert.Len(t, changes[0].GetAllChanges(), 1)
descChange := changes[0].Changes[0]
assert.Equal(t, Modified, descChange.ChangeType)
@@ -288,6 +292,7 @@ tags:
// evaluate.
assert.Equal(t, 1, changes[0].TotalChanges())
assert.Len(t, changes[0].GetAllChanges(), 1)
assert.Equal(t, ObjectAdded, changes[0].Changes[0].ChangeType)
}
@@ -316,6 +321,7 @@ tags:
// evaluate.
assert.Equal(t, 1, changes[0].TotalChanges())
assert.Len(t, changes[0].GetAllChanges(), 1)
assert.Equal(t, ObjectRemoved, changes[0].Changes[0].ChangeType)
}

View File

@@ -14,6 +14,16 @@ type XMLChanges struct {
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
}
// TotalChanges returns a count of everything that was changed within an XML object.
func (x *XMLChanges) TotalChanges() int {
c := x.PropertyChanges.TotalChanges()

View File

@@ -40,6 +40,7 @@ wrapped: true`
// 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)
}
@@ -72,6 +73,7 @@ namespace: something`
// 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())
@@ -107,6 +109,7 @@ x-coffee: time`
// 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)
}

View File

@@ -19,6 +19,7 @@ import (
"github.com/pb33f/libopenapi/datamodel/low/v2"
"github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/what-changed/model"
"reflect"
)
// CompareOpenAPIDocuments will compare left (original) and right (updated) OpenAPI 3+ documents and extract every change
@@ -34,3 +35,23 @@ func CompareOpenAPIDocuments(original, updated *v3.Document) *model.DocumentChan
func CompareSwaggerDocuments(original, updated *v2.Swagger) *model.DocumentChanges {
return model.CompareDocuments(original, updated)
}
func ExtractFlatChanges(changes *model.DocumentChanges) []*model.Change {
return extractChanges(changes)
}
func extractChanges(anything any) []*model.Change {
vo := reflect.ValueOf(anything)
switch vo.Kind() {
case reflect.Ptr:
extractChanges(vo.Elem().Interface())
case reflect.Slice:
panic("slice not supported")
case reflect.Struct:
extractChanges(vo.Elem().Interface())
}
return nil
}