diff --git a/what-changed/contact.go b/what-changed/contact.go index 6488f75..c9021ab 100644 --- a/what-changed/contact.go +++ b/what-changed/contact.go @@ -18,6 +18,11 @@ func (c *ContactChanges) TotalChanges() int { return len(c.Changes) } +// TotalBreakingChanges always returns 0 for Contact objects, they are non-binding. +func (c *ContactChanges) TotalBreakingChanges() int { + return 0 +} + // CompareContact will check a left (original) and right (new) Contact object for any changes. If there // were any, a pointer to a ContactChanges object is returned, otherwise if nothing changed - the function // returns nil. diff --git a/what-changed/contact_test.go b/what-changed/contact_test.go index b3702c1..f4f2d04 100644 --- a/what-changed/contact_test.go +++ b/what-changed/contact_test.go @@ -189,6 +189,7 @@ email: dave@quobix.com` extChanges := CompareContact(&lDoc, &rDoc) assert.Equal(t, 1, extChanges.TotalChanges()) assert.Equal(t, Modified, extChanges.Changes[0].ChangeType) + assert.Equal(t, 0, extChanges.TotalBreakingChanges()) } func TestCompareContact_EmailModifiedAndMoved(t *testing.T) { diff --git a/what-changed/discriminator.go b/what-changed/discriminator.go index 99a63ed..3d09053 100644 --- a/what-changed/discriminator.go +++ b/what-changed/discriminator.go @@ -17,7 +17,7 @@ type DiscriminatorChanges struct { // TotalChanges returns a count of everything changed within the Discriminator object func (d *DiscriminatorChanges) TotalChanges() int { l := 0 - if k := len(d.Changes); k > 0 { + if k := d.PropertyChanges.TotalChanges(); k > 0 { l += k } if k := len(d.MappingChanges); k > 0 { @@ -26,6 +26,13 @@ func (d *DiscriminatorChanges) TotalChanges() int { return l } +// TotalBreakingChanges returns the number of breaking changes made by the Discriminator +func (d *DiscriminatorChanges) TotalBreakingChanges() int { + return d.PropertyChanges.TotalBreakingChanges() + CountBreakingChanges(d.MappingChanges) +} + +// CompareDiscriminator will check a left (original) and right (new) Discriminator object for changes +// and will return a pointer to DiscriminatorChanges func CompareDiscriminator(l, r *base.Discriminator) *DiscriminatorChanges { dc := new(DiscriminatorChanges) var changes []*Change[*base.Discriminator] diff --git a/what-changed/discriminator_test.go b/what-changed/discriminator_test.go index 4e34dc1..e7e6eea 100644 --- a/what-changed/discriminator_test.go +++ b/what-changed/discriminator_test.go @@ -100,13 +100,16 @@ mapping: // compare. extChanges := CompareDiscriminator(&lDoc, &rDoc) assert.Equal(t, 2, extChanges.TotalChanges()) - assert.Equal(t, ObjectAdded, extChanges.MappingChanges[0].ChangeType) - assert.Equal(t, ObjectAdded, extChanges.MappingChanges[1].ChangeType) - assert.Equal(t, "chuffing", extChanges.MappingChanges[0].Property) - assert.Equal(t, "puffing", extChanges.MappingChanges[0].New) - assert.Equal(t, "hacking", extChanges.MappingChanges[1].Property) - assert.Equal(t, "coding", extChanges.MappingChanges[1].New) + for _, k := range extChanges.MappingChanges { + assert.Equal(t, ObjectAdded, k.ChangeType) + if k.Property == "chuffing" { + assert.Equal(t, "puffing", k.New) + } + if k.Property == "hacking" { + assert.Equal(t, "coding", k.New) + } + } } func TestCompareDiscriminator_MappingRemoved(t *testing.T) { @@ -230,7 +233,7 @@ mapping: assert.Equal(t, "puffing", extChanges.MappingChanges[0].Original) // should be a single breaking change - assert.Equal(t, 1, CountBreakingChanges(extChanges.MappingChanges)) + assert.Equal(t, 1, extChanges.TotalBreakingChanges()) } diff --git a/what-changed/extensions.go b/what-changed/extensions.go index f2c010f..4dcc92a 100644 --- a/what-changed/extensions.go +++ b/what-changed/extensions.go @@ -13,6 +13,15 @@ type ExtensionChanges struct { PropertyChanges[any] } +func (e *ExtensionChanges) TotalChanges() int { + return len(e.Changes) +} + +// TotalBreakingChanges always returns 0 for Extension objects, they are non-binding. +func (e *ExtensionChanges) TotalBreakingChanges() int { + return 0 +} + // CompareExtensions will compare a left and right map of Key/ValueReference models for any changes to // anything. This function does not try and cast the value of an extension to perform checks, it // will perform a basic value check. diff --git a/what-changed/extensions_test.go b/what-changed/extensions_test.go index 9adec6e..017a3db 100644 --- a/what-changed/extensions_test.go +++ b/what-changed/extensions_test.go @@ -24,11 +24,12 @@ func TestCompareExtensions(t *testing.T) { extChanges := CompareExtensions(lExt, rExt) - assert.Len(t, extChanges.Changes, 1) + assert.Len(t, extChanges.TotalChanges(), 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) assert.False(t, extChanges.Changes[0].Context.HasChanged()) + assert.Equal(t, 0, extChanges.TotalBreakingChanges()) } func TestCompareExtensions_Removed(t *testing.T) { diff --git a/what-changed/external_docs.go b/what-changed/external_docs.go index 982c7bf..2ceb2ec 100644 --- a/what-changed/external_docs.go +++ b/what-changed/external_docs.go @@ -23,6 +23,11 @@ func (e *ExternalDocChanges) TotalChanges() int { return c } +// TotalBreakingChanges always returns 0 for ExternalDoc objects, they are non-binding. +func (e *ExternalDocChanges) TotalBreakingChanges() int { + return 0 +} + // CompareExternalDocs will compare a left (original) and a right (new) slice of ValueReference // nodes for any changes between them. If there are changes, then a pointer to ExternalDocChanges // is returned, otherwise if nothing changed - then nil is returned. diff --git a/what-changed/external_docs_test.go b/what-changed/external_docs_test.go index 40999dd..a8e9c2a 100644 --- a/what-changed/external_docs_test.go +++ b/what-changed/external_docs_test.go @@ -115,6 +115,7 @@ url: https://quobix.com` assert.True(t, extChange.Context.HasChanged()) assert.Equal(t, "hiya!", extChange.New) assert.Equal(t, "hello", extChange.Original) + assert.Equal(t, 0, extChanges.TotalBreakingChanges()) } func TestCompareExternalDocs_Identical(t *testing.T) { diff --git a/what-changed/info.go b/what-changed/info.go index 355ed7f..749da17 100644 --- a/what-changed/info.go +++ b/what-changed/info.go @@ -27,6 +27,11 @@ func (i *InfoChanges) TotalChanges() int { return t } +// TotalBreakingChanges always returns 0 for Info objects, they are non-binding. +func (i *InfoChanges) TotalBreakingChanges() int { + return 0 +} + func CompareInfo(l, r *base.Info) *InfoChanges { var changes []*Change[*base.Info] diff --git a/what-changed/info_test.go b/what-changed/info_test.go index a86b87c..584e09b 100644 --- a/what-changed/info_test.go +++ b/what-changed/info_test.go @@ -353,6 +353,7 @@ license: assert.Equal(t, 1, extChanges.TotalChanges()) assert.Equal(t, Modified, extChanges.ContactChanges.Changes[0].ChangeType) assert.Equal(t, v3.NameLabel, extChanges.ContactChanges.Changes[0].Property) + assert.Equal(t, 0, extChanges.TotalBreakingChanges()) } func TestCompareInfo_Equal(t *testing.T) { diff --git a/what-changed/license.go b/what-changed/license.go index d0bafbb..4b6c20e 100644 --- a/what-changed/license.go +++ b/what-changed/license.go @@ -18,6 +18,11 @@ func (l *LicenseChanges) TotalChanges() int { return len(l.Changes) } +// TotalBreakingChanges always returns 0 for License objects, they are non-binding. +func (l *LicenseChanges) TotalBreakingChanges() int { + return 0 +} + // CompareLicense will check a left (original) and right (new) License object for any changes. If there // were any, a pointer to a LicenseChanges object is returned, otherwise if nothing changed - the function // returns nil. diff --git a/what-changed/license_test.go b/what-changed/license_test.go index 00def51..d26615a 100644 --- a/what-changed/license_test.go +++ b/what-changed/license_test.go @@ -34,6 +34,7 @@ url: https://pb33f.io` extChanges := CompareLicense(&lDoc, &rDoc) assert.Equal(t, 1, extChanges.TotalChanges()) assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType) + assert.Equal(t, 0, extChanges.TotalBreakingChanges()) } diff --git a/what-changed/models.go b/what-changed/models.go index 216bd80..e6d92bd 100644 --- a/what-changed/models.go +++ b/what-changed/models.go @@ -86,6 +86,16 @@ type PropertyChanges[T any] struct { Changes []*Change[T] } +// TotalChanges returns the total number of property changes made. +func (p PropertyChanges[T]) TotalChanges() int { + return len(p.Changes) +} + +// TotalBreakingChanges returns the total number of property breaking changes made. +func (p PropertyChanges[T]) TotalBreakingChanges() int { + return CountBreakingChanges(p.Changes) +} + // PropertyCheck is used by functions to check the state of left and right values. type PropertyCheck[T any] struct { diff --git a/what-changed/tags.go b/what-changed/tags.go index 21d2e95..a2f0d4f 100644 --- a/what-changed/tags.go +++ b/what-changed/tags.go @@ -29,6 +29,11 @@ func (t *TagChanges) TotalChanges() int { return c } +// TotalBreakingChanges returns the number of breaking changes made by Tags +func (t *TagChanges) TotalBreakingChanges() int { + return t.PropertyChanges.TotalBreakingChanges() +} + // CompareTags will compare a left (original) and a right (new) slice of ValueReference nodes for // any changes between them. If there are changes, a pointer to TagChanges is returned, if not then // nil is returned instead. diff --git a/what-changed/tags_test.go b/what-changed/tags_test.go index dfec172..848e291 100644 --- a/what-changed/tags_test.go +++ b/what-changed/tags_test.go @@ -4,15 +4,15 @@ package what_changed import ( - "github.com/pb33f/libopenapi/datamodel" - lowv3 "github.com/pb33f/libopenapi/datamodel/low/v3" - "github.com/stretchr/testify/assert" - "testing" + "github.com/pb33f/libopenapi/datamodel" + lowv3 "github.com/pb33f/libopenapi/datamodel/low/v3" + "github.com/stretchr/testify/assert" + "testing" ) func TestCompareTags(t *testing.T) { - left := `openapi: 3.0.1 + left := `openapi: 3.0.1 tags: - name: a tag description: a lovely tag @@ -21,7 +21,7 @@ tags: url: https://quobix.com description: cool` - right := `openapi: 3.0.1 + right := `openapi: 3.0.1 tags: - name: a tag description: a lovelier tag description @@ -30,31 +30,31 @@ tags: url: https://pb33f.io description: cooler` - // create document (which will create our correct tags low level structures) - lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) - rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) - lDoc, _ := lowv3.CreateDocument(lInfo) - rDoc, _ := lowv3.CreateDocument(rInfo) + // create document (which will create our correct tags low level structures) + lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) + rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) + lDoc, _ := lowv3.CreateDocument(lInfo) + rDoc, _ := lowv3.CreateDocument(rInfo) - // compare. - changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) + // compare. + changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) - // evaluate. - assert.Len(t, changes.Changes, 1) - assert.Len(t, changes.ExternalDocs.Changes, 2) - assert.Len(t, changes.ExtensionChanges.Changes, 1) - assert.Equal(t, 4, changes.TotalChanges()) + // evaluate. + assert.Len(t, changes.Changes, 1) + assert.Len(t, changes.ExternalDocs.Changes, 2) + assert.Len(t, changes.ExtensionChanges.Changes, 1) + assert.Equal(t, 4, changes.TotalChanges()) - descChange := changes.Changes[0] - assert.Equal(t, "a lovelier tag description", descChange.New) - assert.Equal(t, "a lovely tag", descChange.Original) - assert.Equal(t, Modified, descChange.ChangeType) - assert.False(t, descChange.Context.HasChanged()) + descChange := changes.Changes[0] + assert.Equal(t, "a lovelier tag description", descChange.New) + assert.Equal(t, "a lovely tag", descChange.Original) + assert.Equal(t, Modified, descChange.ChangeType) + assert.False(t, descChange.Context.HasChanged()) } func TestCompareTags_AddNewTag(t *testing.T) { - left := `openapi: 3.0.1 + left := `openapi: 3.0.1 tags: - name: a tag description: a lovelier tag description @@ -63,7 +63,7 @@ tags: url: https://pb33f.io description: cooler` - right := `openapi: 3.0.1 + right := `openapi: 3.0.1 tags: - name: a tag description: a lovelier tag description @@ -74,26 +74,26 @@ tags: - name: a new tag description: a cool new tag` - // create document (which will create our correct tags low level structures) - lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) - rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) - lDoc, _ := lowv3.CreateDocument(lInfo) - rDoc, _ := lowv3.CreateDocument(rInfo) + // create document (which will create our correct tags low level structures) + lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) + rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) + lDoc, _ := lowv3.CreateDocument(lInfo) + rDoc, _ := lowv3.CreateDocument(rInfo) - // compare. - changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) + // compare. + changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) - // evaluate. - assert.Len(t, changes.Changes, 1) - assert.Equal(t, 1, changes.TotalChanges()) + // evaluate. + assert.Len(t, changes.Changes, 1) + assert.Equal(t, 1, changes.TotalChanges()) - descChange := changes.Changes[0] - assert.Equal(t, ObjectAdded, descChange.ChangeType) + descChange := changes.Changes[0] + assert.Equal(t, ObjectAdded, descChange.ChangeType) } func TestCompareTags_AddDeleteTag(t *testing.T) { - left := `openapi: 3.0.1 + left := `openapi: 3.0.1 tags: - name: a tag description: a lovelier tag description @@ -102,31 +102,32 @@ tags: url: https://pb33f.io description: cooler` - right := `openapi: 3.0.1 + right := `openapi: 3.0.1 tags: - name: a new tag description: a cool new tag` - // create document (which will create our correct tags low level structures) - lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) - rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) - lDoc, _ := lowv3.CreateDocument(lInfo) - rDoc, _ := lowv3.CreateDocument(rInfo) + // create document (which will create our correct tags low level structures) + lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) + rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) + lDoc, _ := lowv3.CreateDocument(lInfo) + rDoc, _ := lowv3.CreateDocument(rInfo) - // compare. - changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) + // compare. + changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) - // evaluate. - assert.Len(t, changes.Changes, 2) - assert.Equal(t, 2, changes.TotalChanges()) + // evaluate. + assert.Len(t, changes.Changes, 2) + assert.Equal(t, 2, changes.TotalChanges()) - assert.Equal(t, ObjectRemoved, changes.Changes[0].ChangeType) - assert.Equal(t, ObjectAdded, changes.Changes[1].ChangeType) + assert.Equal(t, ObjectRemoved, changes.Changes[0].ChangeType) + assert.Equal(t, ObjectAdded, changes.Changes[1].ChangeType) + assert.Equal(t, 1, changes.TotalBreakingChanges()) } func TestCompareTags_DescriptionMoved(t *testing.T) { - left := `openapi: 3.0.1 + left := `openapi: 3.0.1 tags: - description: a lovelier tag description name: a tag @@ -135,7 +136,7 @@ tags: url: https://pb33f.io description: cooler` - right := `openapi: 3.0.1 + right := `openapi: 3.0.1 tags: - name: a tag x-tag: something else @@ -144,23 +145,23 @@ tags: url: https://pb33f.io description: cooler` - // create document (which will create our correct tags low level structures) - lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) - rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) - lDoc, _ := lowv3.CreateDocument(lInfo) - rDoc, _ := lowv3.CreateDocument(rInfo) + // create document (which will create our correct tags low level structures) + lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) + rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) + lDoc, _ := lowv3.CreateDocument(lInfo) + rDoc, _ := lowv3.CreateDocument(rInfo) - // compare. - changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) + // compare. + changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) - // evaluate. - assert.Nil(t, changes) + // evaluate. + assert.Nil(t, changes) } func TestCompareTags_NameMoved(t *testing.T) { - left := `openapi: 3.0.1 + left := `openapi: 3.0.1 tags: - description: a lovelier tag description name: a tag @@ -169,7 +170,7 @@ tags: url: https://pb33f.io description: cooler` - right := `openapi: 3.0.1 + right := `openapi: 3.0.1 tags: - description: a lovelier tag description x-tag: something else @@ -178,22 +179,22 @@ tags: description: cooler name: a tag` - // create document (which will create our correct tags low level structures) - lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) - rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) - lDoc, _ := lowv3.CreateDocument(lInfo) - rDoc, _ := lowv3.CreateDocument(rInfo) + // create document (which will create our correct tags low level structures) + lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) + rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) + lDoc, _ := lowv3.CreateDocument(lInfo) + rDoc, _ := lowv3.CreateDocument(rInfo) - // compare. - changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) + // compare. + changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) - // evaluate. - assert.Nil(t, changes) + // evaluate. + assert.Nil(t, changes) } func TestCompareTags_ModifiedAndMoved(t *testing.T) { - left := `openapi: 3.0.1 + left := `openapi: 3.0.1 tags: - description: a lovelier tag description name: a tag @@ -202,7 +203,7 @@ tags: url: https://pb33f.io description: cooler` - right := `openapi: 3.0.1 + right := `openapi: 3.0.1 tags: - name: a tag x-tag: something else @@ -211,29 +212,29 @@ tags: url: https://pb33f.io description: cooler` - // create document (which will create our correct tags low level structures) - lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) - rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) - lDoc, _ := lowv3.CreateDocument(lInfo) - rDoc, _ := lowv3.CreateDocument(rInfo) + // create document (which will create our correct tags low level structures) + lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) + rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) + lDoc, _ := lowv3.CreateDocument(lInfo) + rDoc, _ := lowv3.CreateDocument(rInfo) - // compare. - changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) + // compare. + changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) - // evaluate. - assert.Len(t, changes.Changes, 1) - assert.Equal(t, 1, changes.TotalChanges()) + // evaluate. + assert.Len(t, changes.Changes, 1) + assert.Equal(t, 1, changes.TotalChanges()) - descChange := changes.Changes[0] - assert.Equal(t, Modified, descChange.ChangeType) - assert.Equal(t, "a lovelier tag description", descChange.Original) - assert.Equal(t, "a different tag description", descChange.New) - assert.True(t, descChange.Context.HasChanged()) + descChange := changes.Changes[0] + assert.Equal(t, Modified, descChange.ChangeType) + assert.Equal(t, "a lovelier tag description", descChange.Original) + assert.Equal(t, "a different tag description", descChange.New) + assert.True(t, descChange.Context.HasChanged()) } func TestCompareTags_Identical(t *testing.T) { - left := `openapi: 3.0.1 + left := `openapi: 3.0.1 tags: - description: a lovelier tag description name: a tag @@ -242,7 +243,7 @@ tags: url: https://pb33f.io description: cooler` - right := `openapi: 3.0.1 + right := `openapi: 3.0.1 tags: - description: a lovelier tag description name: a tag @@ -251,16 +252,16 @@ tags: url: https://pb33f.io description: cooler` - // create document (which will create our correct tags low level structures) - lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) - rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) - lDoc, _ := lowv3.CreateDocument(lInfo) - rDoc, _ := lowv3.CreateDocument(rInfo) + // create document (which will create our correct tags low level structures) + lInfo, _ := datamodel.ExtractSpecInfo([]byte(left)) + rInfo, _ := datamodel.ExtractSpecInfo([]byte(right)) + lDoc, _ := lowv3.CreateDocument(lInfo) + rDoc, _ := lowv3.CreateDocument(rInfo) - // compare. - changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) + // compare. + changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value) - // evaluate. - assert.Nil(t, changes) + // evaluate. + assert.Nil(t, changes) } diff --git a/what-changed/xml.go b/what-changed/xml.go index 67caf40..d68ef5d 100644 --- a/what-changed/xml.go +++ b/what-changed/xml.go @@ -23,6 +23,11 @@ func (x *XMLChanges) TotalChanges() int { return c } +// TotalBreakingChanges returns the number of breaking changes made by the XML object. +func (x *XMLChanges) TotalBreakingChanges() int { + return x.PropertyChanges.TotalBreakingChanges() +} + // CompareXML will compare a left (original) and a right (new) XML instance, and check for // any changes between them. If changes are found, the function returns a pointer to XMLChanges, // otherwise, if nothing changed - it will return nil diff --git a/what-changed/xml_test.go b/what-changed/xml_test.go index e7da3fb..d7b7f34 100644 --- a/what-changed/xml_test.go +++ b/what-changed/xml_test.go @@ -73,6 +73,7 @@ namespace: something` extChanges := CompareXML(&lDoc, &rDoc) assert.Equal(t, 1, extChanges.TotalChanges()) assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType) + assert.Equal(t, 1, extChanges.TotalBreakingChanges()) }