mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-09 12:37:49 +00:00
what-changed code in place.
Let the explosions begin!
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
type hotdog struct {
|
type hotdog struct {
|
||||||
Name NodeReference[string]
|
Name NodeReference[string]
|
||||||
|
ValueName ValueReference[string]
|
||||||
Fat NodeReference[int]
|
Fat NodeReference[int]
|
||||||
Ketchup NodeReference[float32]
|
Ketchup NodeReference[float32]
|
||||||
Mustard NodeReference[float64]
|
Mustard NodeReference[float64]
|
||||||
@@ -46,6 +47,7 @@ func TestBuildModel_Mismatch(t *testing.T) {
|
|||||||
func TestBuildModel(t *testing.T) {
|
func TestBuildModel(t *testing.T) {
|
||||||
|
|
||||||
yml := `name: yummy
|
yml := `name: yummy
|
||||||
|
valueName: yammy
|
||||||
beef: true
|
beef: true
|
||||||
fat: 200
|
fat: 200
|
||||||
ketchup: 200.45
|
ketchup: 200.45
|
||||||
@@ -106,9 +108,10 @@ there:
|
|||||||
hd := hotdog{}
|
hd := hotdog{}
|
||||||
cErr := BuildModel(rootNode.Content[0], &hd)
|
cErr := BuildModel(rootNode.Content[0], &hd)
|
||||||
assert.Equal(t, 200, hd.Fat.Value)
|
assert.Equal(t, 200, hd.Fat.Value)
|
||||||
assert.Equal(t, 3, hd.Fat.ValueNode.Line)
|
assert.Equal(t, 4, hd.Fat.ValueNode.Line)
|
||||||
assert.Equal(t, true, hd.Grilled.Value)
|
assert.Equal(t, true, hd.Grilled.Value)
|
||||||
assert.Equal(t, "yummy", hd.Name.Value)
|
assert.Equal(t, "yummy", hd.Name.Value)
|
||||||
|
assert.Equal(t, "yammy", hd.ValueName.Value)
|
||||||
assert.Equal(t, float32(200.45), hd.Ketchup.Value)
|
assert.Equal(t, float32(200.45), hd.Ketchup.Value)
|
||||||
assert.Len(t, hd.Drinks, 3)
|
assert.Len(t, hd.Drinks, 3)
|
||||||
assert.Len(t, hd.Sides, 4)
|
assert.Len(t, hd.Sides, 4)
|
||||||
@@ -119,7 +122,7 @@ there:
|
|||||||
assert.Len(t, hd.MaxTempAlt, 5)
|
assert.Len(t, hd.MaxTempAlt, 5)
|
||||||
assert.Equal(t, int64(7392837462032342), hd.MaxTempHigh.Value)
|
assert.Equal(t, int64(7392837462032342), hd.MaxTempHigh.Value)
|
||||||
assert.Equal(t, 2, hd.Temps[1].Value)
|
assert.Equal(t, 2, hd.Temps[1].Value)
|
||||||
assert.Equal(t, 26, hd.Temps[1].ValueNode.Line)
|
assert.Equal(t, 27, hd.Temps[1].ValueNode.Line)
|
||||||
assert.Len(t, hd.UnknownElements.Value, 2)
|
assert.Len(t, hd.UnknownElements.Value, 2)
|
||||||
assert.Len(t, hd.LotsOfUnknowns, 3)
|
assert.Len(t, hd.LotsOfUnknowns, 3)
|
||||||
assert.Len(t, hd.Where, 2)
|
assert.Len(t, hd.Where, 2)
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ func TestCreateDocument(t *testing.T) {
|
|||||||
assert.Equal(t, "http://swagger.io", doc.ExternalDocs.Value.URL.Value)
|
assert.Equal(t, "http://swagger.io", doc.ExternalDocs.Value.URL.Value)
|
||||||
assert.Equal(t, true, doc.FindExtension("x-pet").Value)
|
assert.Equal(t, true, doc.FindExtension("x-pet").Value)
|
||||||
assert.Equal(t, true, doc.FindExtension("X-Pet").Value)
|
assert.Equal(t, true, doc.FindExtension("X-Pet").Value)
|
||||||
|
assert.NotNil(t, doc.GetExternalDocs())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_Info(t *testing.T) {
|
func TestCreateDocument_Info(t *testing.T) {
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ type componentBuildResult[T any] struct {
|
|||||||
|
|
||||||
func extractComponentValues[T low.Buildable[N], N any](label string, root *yaml.Node,
|
func extractComponentValues[T low.Buildable[N], N any](label string, root *yaml.Node,
|
||||||
skip chan bool, errorChan chan<- error, resultChan chan<- low.NodeReference[map[low.KeyReference[string]]low.ValueReference[T]], idx *index.SpecIndex) {
|
skip chan bool, errorChan chan<- error, resultChan chan<- low.NodeReference[map[low.KeyReference[string]]low.ValueReference[T]], idx *index.SpecIndex) {
|
||||||
_, nodeLabel, nodeValue := utils.FindKeyNodeFull(label, root.Content)
|
_, nodeLabel, nodeValue := utils.FindKeyNodeFullTop(label, root.Content)
|
||||||
if nodeValue == nil {
|
if nodeValue == nil {
|
||||||
skip <- true
|
skip <- true
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testComponentsYaml = `components:
|
var testComponentsYaml = `
|
||||||
|
x-pizza: crispy
|
||||||
schemas:
|
schemas:
|
||||||
one:
|
one:
|
||||||
description: one of many
|
description: one of many
|
||||||
@@ -97,6 +98,9 @@ func TestComponents_Build_Success(t *testing.T) {
|
|||||||
assert.Equal(t, "eighteen of many",
|
assert.Equal(t, "eighteen of many",
|
||||||
n.FindCallback("eighteen").Value.FindExpression("{raference}").Value.Post.Value.Description.Value)
|
n.FindCallback("eighteen").Value.FindExpression("{raference}").Value.Post.Value.Description.Value)
|
||||||
|
|
||||||
|
assert.Equal(t, "7add1a6c63a354b1a8ffe22552c213fe26d1229beb0b0cbe7c7ca06e63f9a364",
|
||||||
|
low.GenerateHashString(&n))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestComponents_Build_Success_Skip(t *testing.T) {
|
func TestComponents_Build_Success_Skip(t *testing.T) {
|
||||||
@@ -119,7 +123,7 @@ func TestComponents_Build_Success_Skip(t *testing.T) {
|
|||||||
|
|
||||||
func TestComponents_Build_Fail(t *testing.T) {
|
func TestComponents_Build_Fail(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `
|
||||||
parameters:
|
parameters:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/this is a problem.'`
|
$ref: '#/this is a problem.'`
|
||||||
@@ -140,7 +144,7 @@ func TestComponents_Build_Fail(t *testing.T) {
|
|||||||
|
|
||||||
func TestComponents_Build_ParameterFail(t *testing.T) {
|
func TestComponents_Build_ParameterFail(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `
|
||||||
parameters:
|
parameters:
|
||||||
pizza:
|
pizza:
|
||||||
schema:
|
schema:
|
||||||
@@ -162,7 +166,7 @@ func TestComponents_Build_ParameterFail(t *testing.T) {
|
|||||||
|
|
||||||
func TestComponents_Build_Fail_TypeFail(t *testing.T) {
|
func TestComponents_Build_Fail_TypeFail(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `
|
||||||
parameters:
|
parameters:
|
||||||
- schema:
|
- schema:
|
||||||
$ref: #/this is a problem.`
|
$ref: #/this is a problem.`
|
||||||
@@ -178,7 +182,6 @@ func TestComponents_Build_Fail_TypeFail(t *testing.T) {
|
|||||||
|
|
||||||
err = n.Build(idxNode.Content[0], idx)
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestComponents_Build_ExtensionTest(t *testing.T) {
|
func TestComponents_Build_ExtensionTest(t *testing.T) {
|
||||||
@@ -201,3 +204,25 @@ headers:
|
|||||||
assert.Equal(t, "seagull", n.FindExtension("x-curry").Value)
|
assert.Equal(t, "seagull", n.FindExtension("x-curry").Value)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestComponents_Build_HashEmpty(t *testing.T) {
|
||||||
|
|
||||||
|
yml := `x-curry: seagull`
|
||||||
|
|
||||||
|
var idxNode yaml.Node
|
||||||
|
mErr := yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
assert.NoError(t, mErr)
|
||||||
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
|
var n Components
|
||||||
|
err := low.BuildModel(&idxNode, &n)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = n.Build(idxNode.Content[0], idx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "seagull", n.FindExtension("x-curry").Value)
|
||||||
|
|
||||||
|
assert.Equal(t, "9cf2c6ab3f9ff7e5231fcb391c8af5c47406711d2ca366533f21a8bb2f67edfe",
|
||||||
|
low.GenerateHashString(&n))
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -477,6 +477,9 @@ func TestCreateDocument_Component_Discriminator(t *testing.T) {
|
|||||||
assert.Equal(t, "drinkType", dsc.PropertyName.Value)
|
assert.Equal(t, "drinkType", dsc.PropertyName.Value)
|
||||||
assert.Equal(t, "some value", dsc.FindMappingValue("drink").Value)
|
assert.Equal(t, "some value", dsc.FindMappingValue("drink").Value)
|
||||||
assert.Nil(t, dsc.FindMappingValue("don't exist"))
|
assert.Nil(t, dsc.FindMappingValue("don't exist"))
|
||||||
|
assert.NotNil(t, doc.GetExternalDocs())
|
||||||
|
assert.Nil(t, doc.FindSecurityRequirement("scooby doo"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_CheckAdditionalProperties_Schema(t *testing.T) {
|
func TestCreateDocument_CheckAdditionalProperties_Schema(t *testing.T) {
|
||||||
@@ -518,8 +521,21 @@ components:
|
|||||||
assert.Error(t, ob.GetBuildError())
|
assert.Error(t, ob.GetBuildError())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateDocument_Webhooks_Error(t *testing.T) {
|
||||||
|
yml := `openapi: 3.0
|
||||||
|
webhooks:
|
||||||
|
aHook:
|
||||||
|
$ref: #bork`
|
||||||
|
|
||||||
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
||||||
|
var err []error
|
||||||
|
doc, err = CreateDocument(info)
|
||||||
|
assert.Len(t, err, 1)
|
||||||
|
}
|
||||||
|
|
||||||
func TestCreateDocument_Components_Error_Extract(t *testing.T) {
|
func TestCreateDocument_Components_Error_Extract(t *testing.T) {
|
||||||
yml := `components:
|
yml := `openapi: 3.0
|
||||||
|
components:
|
||||||
parameters:
|
parameters:
|
||||||
bork:
|
bork:
|
||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
@@ -532,7 +548,8 @@ func TestCreateDocument_Components_Error_Extract(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_Paths_Errors(t *testing.T) {
|
func TestCreateDocument_Paths_Errors(t *testing.T) {
|
||||||
yml := `paths:
|
yml := `openapi: 3.0
|
||||||
|
paths:
|
||||||
/p:
|
/p:
|
||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
|
|
||||||
@@ -543,7 +560,8 @@ func TestCreateDocument_Paths_Errors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_Tags_Errors(t *testing.T) {
|
func TestCreateDocument_Tags_Errors(t *testing.T) {
|
||||||
yml := `tags:
|
yml := `openapi: 3.0
|
||||||
|
tags:
|
||||||
- $ref: #bork`
|
- $ref: #bork`
|
||||||
|
|
||||||
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
||||||
@@ -553,7 +571,8 @@ func TestCreateDocument_Tags_Errors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_Security_Error(t *testing.T) {
|
func TestCreateDocument_Security_Error(t *testing.T) {
|
||||||
yml := `security:
|
yml := `openapi: 3.0
|
||||||
|
security:
|
||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
|
|
||||||
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
||||||
@@ -563,7 +582,8 @@ func TestCreateDocument_Security_Error(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_ExternalDoc_Error(t *testing.T) {
|
func TestCreateDocument_ExternalDoc_Error(t *testing.T) {
|
||||||
yml := `externalDocs:
|
yml := `openapi: 3.0
|
||||||
|
externalDocs:
|
||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
|
|
||||||
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
||||||
|
|||||||
548
test_specs/burgershop.openapi-modified.yaml
Normal file
548
test_specs/burgershop.openapi-modified.yaml
Normal file
@@ -0,0 +1,548 @@
|
|||||||
|
openapi: 3.1.0
|
||||||
|
info:
|
||||||
|
title: Burger Shop
|
||||||
|
description: |
|
||||||
|
The best burger API at princess beef. You can find the testiest burgers in the world
|
||||||
|
termsOfService: https://pb33f.io
|
||||||
|
contact:
|
||||||
|
name: pb33f
|
||||||
|
email: buckaroo@pb33f.io
|
||||||
|
url: https://pb33f.io
|
||||||
|
license:
|
||||||
|
name: pb33f
|
||||||
|
url: https://pb33f.io/made-up
|
||||||
|
version: "1.2"
|
||||||
|
security:
|
||||||
|
- OAuthScheme:
|
||||||
|
- read:burgers
|
||||||
|
- write:burgers
|
||||||
|
tags:
|
||||||
|
- name: "Burgers"
|
||||||
|
description: "All kinds of yummy burgers."
|
||||||
|
externalDocs:
|
||||||
|
description: "Find out more"
|
||||||
|
url: "https://pb33f.io"
|
||||||
|
x-internal-ting: somethingSpecial
|
||||||
|
x-internal-tong: 1
|
||||||
|
x-internal-tang: 1.2
|
||||||
|
x-internal-tung: true
|
||||||
|
x-internal-arr:
|
||||||
|
- one
|
||||||
|
- two
|
||||||
|
x-internal-arrmap:
|
||||||
|
- what: now
|
||||||
|
- why: that
|
||||||
|
x-something-else:
|
||||||
|
ok:
|
||||||
|
- what: now?
|
||||||
|
- name: "Dressing"
|
||||||
|
description: "Variety of dressings: cheese, veggie, oil and a lot more"
|
||||||
|
externalDocs:
|
||||||
|
description: "Find out more information about our products)"
|
||||||
|
url: "https://pb33f.io"
|
||||||
|
servers:
|
||||||
|
- url: "{scheme}://api.pb33f.io"
|
||||||
|
description: "this is our main API server, for all fun API things."
|
||||||
|
variables:
|
||||||
|
scheme:
|
||||||
|
enum: [https, wss]
|
||||||
|
default: https
|
||||||
|
description: this is a server variable for the scheme
|
||||||
|
- url: "https://{domain}.{host}.com"
|
||||||
|
description: "this is our second API server, for all fun API things."
|
||||||
|
variables:
|
||||||
|
domain:
|
||||||
|
default: "api"
|
||||||
|
description: the default API domain is 'api'
|
||||||
|
host:
|
||||||
|
default: "pb33f.io"
|
||||||
|
description: the default host for this API is 'pb33f.io'
|
||||||
|
paths:
|
||||||
|
x-milky-milk: milky
|
||||||
|
/burgers:
|
||||||
|
x-burger-meta: meaty
|
||||||
|
post:
|
||||||
|
operationId: createBurger
|
||||||
|
tags:
|
||||||
|
- "Burgers"
|
||||||
|
summary: Create a new burger
|
||||||
|
description: A new burger for our menu, yummy yum yum.
|
||||||
|
requestBody:
|
||||||
|
$ref: '#/components/requestBodies/BurgerRequest'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
headers:
|
||||||
|
UseOil:
|
||||||
|
$ref: '#/components/headers/UseOil'
|
||||||
|
description: A tasty burger for you to eat.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Burger'
|
||||||
|
examples:
|
||||||
|
quarterPounder:
|
||||||
|
$ref: '#/components/examples/QuarterPounder'
|
||||||
|
filetOFish:
|
||||||
|
summary: a cripsy fish sammich filled with ocean goodness.
|
||||||
|
value:
|
||||||
|
name: Filet-O-Fish
|
||||||
|
numPatties: 1
|
||||||
|
links:
|
||||||
|
LocateBurger:
|
||||||
|
$ref: '#/components/links/LocateBurger'
|
||||||
|
AnotherLocateBurger:
|
||||||
|
$ref: '#/components/links/AnotherLocateBurger'
|
||||||
|
"500":
|
||||||
|
description: Unexpected error creating a new burger. Sorry.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
examples:
|
||||||
|
unexpectedError:
|
||||||
|
summary: oh my goodness
|
||||||
|
value:
|
||||||
|
message: something went terribly wrong my friend, no new burger for you.
|
||||||
|
"422":
|
||||||
|
description: Unprocessable entity
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
examples:
|
||||||
|
unexpectedError:
|
||||||
|
summary: invalid request
|
||||||
|
value:
|
||||||
|
message: unable to accept this request, looks bad, missing something.
|
||||||
|
security:
|
||||||
|
- OAuthScheme:
|
||||||
|
- read:burgers
|
||||||
|
- write:burgers
|
||||||
|
servers:
|
||||||
|
- url: https://pb33f.io
|
||||||
|
description: this is an alternative server for this operation.
|
||||||
|
/burgers/{burgerId}:
|
||||||
|
get:
|
||||||
|
callbacks:
|
||||||
|
burgerCallback:
|
||||||
|
$ref: '#/components/callbacks/BurgerCallback'
|
||||||
|
operationId: locateBurger
|
||||||
|
tags:
|
||||||
|
- "Burgers"
|
||||||
|
summary: Search a burger by ID - returns the burger with that identifier
|
||||||
|
description: Look up a tasty burger take it and enjoy it
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/BurgerId'
|
||||||
|
- $ref: '#/components/parameters/BurgerHeader'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: A tasty burger for you to eat. Wide variety of products to choose from
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Burger'
|
||||||
|
examples:
|
||||||
|
quarterPounder:
|
||||||
|
$ref: '#/components/examples/QuarterPounder'
|
||||||
|
filetOFish:
|
||||||
|
summary: A tasty treat from the sea
|
||||||
|
value:
|
||||||
|
name: Filet-O-Fish
|
||||||
|
numPatties: 1
|
||||||
|
links:
|
||||||
|
ListBurgerDressings:
|
||||||
|
operationId: listBurgerDressings
|
||||||
|
parameters:
|
||||||
|
dressingId: 'something here'
|
||||||
|
description: 'Try the ketchup!'
|
||||||
|
"404":
|
||||||
|
description: Cannot find your burger. Sorry. We may have sold out of this type
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
examples:
|
||||||
|
notFound:
|
||||||
|
summary: burger missing
|
||||||
|
value:
|
||||||
|
message: can't find a burger with that ID, we may have sold out my friend.
|
||||||
|
"500":
|
||||||
|
description: Unexpected error. Sorry.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
examples:
|
||||||
|
unexpectedError:
|
||||||
|
summary: oh my stars
|
||||||
|
value:
|
||||||
|
message: something went terribly wrong my friend, burger location crashed!
|
||||||
|
/burgers/{burgerId}/dressings:
|
||||||
|
get:
|
||||||
|
operationId: listBurgerDressings
|
||||||
|
tags:
|
||||||
|
- "Dressing"
|
||||||
|
summary: Get a list of all dressings available
|
||||||
|
description: Same as the summary, look up a tasty burger, by its ID - the burger identifier
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: burgerId
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: big-mac
|
||||||
|
description: the name of the our fantastic burger. You can pick a name from our menu
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
$ref: '#/components/responses/DressingResponse'
|
||||||
|
"404":
|
||||||
|
description: Cannot find your burger in which to list dressings. Sorry
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
example:
|
||||||
|
message: There is no burger here
|
||||||
|
"500":
|
||||||
|
description: Unexpected error listing dressings for burger. Sorry.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
example:
|
||||||
|
message: computer says no dressings for this burger.
|
||||||
|
/dressings/{dressingId}:
|
||||||
|
get:
|
||||||
|
operationId: getDressing
|
||||||
|
tags:
|
||||||
|
- "Dressing"
|
||||||
|
summary: Get a specific dressing - you can choose the dressing from our menu
|
||||||
|
description: Same as the summary, get a dressing, by its ID
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: dressingId
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: cheese
|
||||||
|
description: This is the unique identifier for the dressing items.
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: a dressing
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Dressing'
|
||||||
|
example:
|
||||||
|
name: Butter Sauce
|
||||||
|
"404":
|
||||||
|
description: Cannot find your dressing, sorry.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
example:
|
||||||
|
message: No such dressing as 'Pizza'
|
||||||
|
"500":
|
||||||
|
description: Unexpected error getting a dressing. Sorry.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
example:
|
||||||
|
message: failed looking up dressing by ID, our server borked.
|
||||||
|
/dressings:
|
||||||
|
get:
|
||||||
|
operationId: getAllDressings
|
||||||
|
tags:
|
||||||
|
- "Dressing"
|
||||||
|
summary: Get all dressings available in our store
|
||||||
|
description: Get all dressings and choose from them
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: an array of dressings
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Dressing'
|
||||||
|
example:
|
||||||
|
- name: Burger Sauce
|
||||||
|
"418":
|
||||||
|
description: I am a teapot.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
example:
|
||||||
|
message: It's teapot time.
|
||||||
|
"500":
|
||||||
|
description: Something went wrong with getting dressings.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
example:
|
||||||
|
message: "failed looking up all dressings, something went wrong."
|
||||||
|
components:
|
||||||
|
callbacks:
|
||||||
|
BurgerCallback:
|
||||||
|
x-break-everything: please
|
||||||
|
"{$request.query.queryUrl}":
|
||||||
|
post:
|
||||||
|
requestBody:
|
||||||
|
description: Callback payload
|
||||||
|
content:
|
||||||
|
'application/json':
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/SomePayload'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: callback successfully processes
|
||||||
|
links:
|
||||||
|
LocateBurger:
|
||||||
|
operationId: locateBurger
|
||||||
|
parameters:
|
||||||
|
burgerId: '$response.body#/id'
|
||||||
|
description: Go and get a tasty burger
|
||||||
|
AnotherLocateBurger:
|
||||||
|
operationId: locateBurger
|
||||||
|
parameters:
|
||||||
|
burgerId: '$response.body#/id'
|
||||||
|
description: Go and get another really tasty burger
|
||||||
|
server:
|
||||||
|
url: https://pb33f.io
|
||||||
|
headers:
|
||||||
|
UseOil:
|
||||||
|
description: this is a header example for UseOil
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
requestBodies:
|
||||||
|
BurgerRequest:
|
||||||
|
description: Give us the new burger!
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Burger'
|
||||||
|
examples:
|
||||||
|
pbjBurger:
|
||||||
|
summary: A horrible, nutty, sticky mess.
|
||||||
|
value:
|
||||||
|
name: Peanut And Jelly
|
||||||
|
numPatties: 3
|
||||||
|
cakeBurger:
|
||||||
|
summary: A sickly, sweet, atrocity
|
||||||
|
value:
|
||||||
|
name: Chocolate Cake Burger
|
||||||
|
numPatties: 5
|
||||||
|
examples:
|
||||||
|
QuarterPounder:
|
||||||
|
summary: A juicy two hander sammich
|
||||||
|
value:
|
||||||
|
name: Quarter Pounder with Cheese
|
||||||
|
numPatties: 1
|
||||||
|
responses:
|
||||||
|
DressingResponse:
|
||||||
|
description: all the dressings for a burger.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Dressing'
|
||||||
|
example:
|
||||||
|
- name: Thousand Island
|
||||||
|
securitySchemes:
|
||||||
|
APIKeyScheme:
|
||||||
|
type: apiKey
|
||||||
|
description: an apiKey security scheme
|
||||||
|
name: apiKeyScheme
|
||||||
|
in: query
|
||||||
|
JWTScheme:
|
||||||
|
type: http
|
||||||
|
description: an JWT security scheme
|
||||||
|
name: aJWTThing
|
||||||
|
scheme: bearer
|
||||||
|
bearerFormat: JWT
|
||||||
|
OAuthScheme:
|
||||||
|
type: oauth2
|
||||||
|
description: an oAuth security scheme
|
||||||
|
name: oAuthy
|
||||||
|
flows:
|
||||||
|
implicit:
|
||||||
|
authorizationUrl: https://pb33f.io/oauth
|
||||||
|
scopes:
|
||||||
|
write:burgers: modify and add new burgers
|
||||||
|
read:burgers: read all burgers
|
||||||
|
authorizationCode:
|
||||||
|
authorizationUrl: https://pb33f.io/oauth
|
||||||
|
tokenUrl: https://api.pb33f.io/oauth/token
|
||||||
|
scopes:
|
||||||
|
write:burgers: modify burgers and stuff
|
||||||
|
read:burgers: read all the burgers
|
||||||
|
parameters:
|
||||||
|
BurgerHeader:
|
||||||
|
in: header
|
||||||
|
name: burgerHeader
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
burgerTheme:
|
||||||
|
type: string
|
||||||
|
description: something about a theme goes in here?
|
||||||
|
burgerTime:
|
||||||
|
type: number
|
||||||
|
description: number of burgers ordered so far this year.
|
||||||
|
example: big-mac
|
||||||
|
description: the name of the burger. use this to order your food
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
example: somethingNice
|
||||||
|
encoding:
|
||||||
|
burgerTheme:
|
||||||
|
contentType: text/plain
|
||||||
|
headers:
|
||||||
|
someHeader:
|
||||||
|
description: this is a header
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
required: [burgerTheme, burgerTime]
|
||||||
|
properties:
|
||||||
|
burgerTheme:
|
||||||
|
type: string
|
||||||
|
description: something about a theme?
|
||||||
|
burgerTime:
|
||||||
|
type: number
|
||||||
|
description: number of burgers ordered this year.
|
||||||
|
BurgerId:
|
||||||
|
in: path
|
||||||
|
name: burgerId
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: big-mac
|
||||||
|
description: the name of the burger. use this to order your tasty burger
|
||||||
|
required: true
|
||||||
|
schemas:
|
||||||
|
Error:
|
||||||
|
type: object
|
||||||
|
description: Error defining what went wrong when providing a specification. The message should help indicate the issue clearly.
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
description: returns the error message if something wrong happens
|
||||||
|
example: No such burger as 'Big-Whopper'
|
||||||
|
Burger:
|
||||||
|
type: object
|
||||||
|
description: The tastiest food on the planet you would love to eat everyday
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- numPatties
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The name of your tasty burger - burger names are listed in our menus
|
||||||
|
example: Big Mac
|
||||||
|
numPatties:
|
||||||
|
type: integer
|
||||||
|
description: The number of burger patties used
|
||||||
|
example: 2
|
||||||
|
numTomatoes:
|
||||||
|
type: integer
|
||||||
|
description: how many slices of orange goodness would you like?
|
||||||
|
example: 1
|
||||||
|
fries:
|
||||||
|
$ref: '#/components/schemas/Fries'
|
||||||
|
Fries:
|
||||||
|
type: object
|
||||||
|
description: golden slices of happy fun joy
|
||||||
|
required:
|
||||||
|
- potatoShape
|
||||||
|
- favoriteDrink
|
||||||
|
properties:
|
||||||
|
seasoning:
|
||||||
|
type: array
|
||||||
|
description: herbs and spices for your golden joy
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
description: type of herb or spice used to liven up the yummy
|
||||||
|
example: salt
|
||||||
|
potatoShape:
|
||||||
|
type: string
|
||||||
|
description: what type of potato shape? wedges? shoestring?
|
||||||
|
example: Crispy Shoestring
|
||||||
|
favoriteDrink:
|
||||||
|
$ref: '#/components/schemas/Drink'
|
||||||
|
Dressing:
|
||||||
|
type: object
|
||||||
|
description: This is the object that contains the information about the content of the dressing
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The name of your dressing you can pick up from the menu
|
||||||
|
example: Cheese
|
||||||
|
additionalProperties:
|
||||||
|
type: object
|
||||||
|
description: something in here.
|
||||||
|
Drink:
|
||||||
|
type: object
|
||||||
|
description: a frosty cold beverage can be coke or sprite
|
||||||
|
required:
|
||||||
|
- size
|
||||||
|
- drinkType
|
||||||
|
properties:
|
||||||
|
ice:
|
||||||
|
type: boolean
|
||||||
|
drinkType:
|
||||||
|
description: select from coke or sprite
|
||||||
|
enum:
|
||||||
|
- coke
|
||||||
|
- sprite
|
||||||
|
size:
|
||||||
|
type: string
|
||||||
|
description: what size man? S/M/L
|
||||||
|
example: M
|
||||||
|
additionalProperties: true
|
||||||
|
discriminator:
|
||||||
|
propertyName: drinkType
|
||||||
|
mapping:
|
||||||
|
drink: some value
|
||||||
|
SomePayload:
|
||||||
|
type: string
|
||||||
|
description: some kind of payload for something.
|
||||||
|
xml:
|
||||||
|
name: is html programming? yes.
|
||||||
|
externalDocs:
|
||||||
|
url: https://pb33f.io/docs
|
||||||
|
oneOf:
|
||||||
|
- $ref: '#/components/schemas/Drink'
|
||||||
|
anyOf:
|
||||||
|
- $ref: '#/components/schemas/Drink'
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/components/schemas/Drink'
|
||||||
|
not:
|
||||||
|
type: string
|
||||||
|
items:
|
||||||
|
- $ref: '#/components/schemas/Drink'
|
||||||
|
x-screaming-baby: loud
|
||||||
|
x-something-something: darkside
|
||||||
|
externalDocs:
|
||||||
|
description: "Find out more information about our products and services"
|
||||||
|
url: "https://pb33f.io"
|
||||||
|
jsonSchemaDialect: https://pb33f.io/schema
|
||||||
|
webhooks:
|
||||||
|
someHook:
|
||||||
|
post:
|
||||||
|
requestBody:
|
||||||
|
description: Information about a new burger
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/Burger"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: the hook is good! you have a new burger.
|
||||||
@@ -31,7 +31,7 @@ components:
|
|||||||
yester:
|
yester:
|
||||||
"$ref": "#/components/schemas/Seven"
|
"$ref": "#/components/schemas/Seven"
|
||||||
Four:
|
Four:
|
||||||
desription: "test four"
|
description: "test four"
|
||||||
properties:
|
properties:
|
||||||
lemons:
|
lemons:
|
||||||
"$ref": "#/components/schemas/Nine"
|
"$ref": "#/components/schemas/Nine"
|
||||||
|
|||||||
@@ -100,10 +100,6 @@ func CompareComponents(l, r any) *ComponentsChanges {
|
|||||||
lComponents := l.(*v3.Components)
|
lComponents := l.(*v3.Components)
|
||||||
rComponents := r.(*v3.Components)
|
rComponents := r.(*v3.Components)
|
||||||
|
|
||||||
if lComponents == nil && rComponents == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if low.AreEqual(lComponents, rComponents) {
|
if low.AreEqual(lComponents, rComponents) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,6 +203,14 @@ func CompareDocuments(l, r any) *DocumentChanges {
|
|||||||
dc.ComponentsChanges = n
|
dc.ComponentsChanges = n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !lDoc.Components.IsEmpty() && rDoc.Components.IsEmpty() {
|
||||||
|
CreateChange(&changes, PropertyRemoved, v3.ComponentsLabel,
|
||||||
|
lDoc.Components.ValueNode, nil, true, lDoc.Components.Value, nil)
|
||||||
|
}
|
||||||
|
if lDoc.Components.IsEmpty() && !rDoc.Components.IsEmpty() {
|
||||||
|
CreateChange(&changes, PropertyAdded, v3.ComponentsLabel,
|
||||||
|
rDoc.Components.ValueNode, nil, false, nil, lDoc.Components.Value)
|
||||||
|
}
|
||||||
|
|
||||||
// compare servers
|
// compare servers
|
||||||
if n := checkServers(lDoc.Servers, rDoc.Servers, &changes); n != nil {
|
if n := checkServers(lDoc.Servers, rDoc.Servers, &changes); n != nil {
|
||||||
@@ -210,7 +218,10 @@ func CompareDocuments(l, r any) *DocumentChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compare webhooks
|
// compare webhooks
|
||||||
CheckMapForChanges(lDoc.Webhooks.Value, rDoc.Webhooks.Value, &changes, v3.WebhooksLabel, ComparePathItemsV3)
|
dc.WebhookChanges = CheckMapForChanges(lDoc.Webhooks.Value, rDoc.Webhooks.Value, &changes,
|
||||||
|
v3.WebhooksLabel, ComparePathItemsV3)
|
||||||
|
|
||||||
|
// extensions
|
||||||
dc.ExtensionChanges = CompareExtensions(lDoc.Extensions, rDoc.Extensions)
|
dc.ExtensionChanges = CompareExtensions(lDoc.Extensions, rDoc.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -216,6 +216,8 @@ externalDocs:
|
|||||||
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||||
assert.Equal(t, v3.ExternalDocsLabel, extChanges.Changes[0].Property)
|
assert.Equal(t, v3.ExternalDocsLabel, extChanges.Changes[0].Property)
|
||||||
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
|
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
|
||||||
|
assert.NotNil(t, lDoc.GetExternalDocs())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompareDocuments_Swagger_ExternalDocs_Removed(t *testing.T) {
|
func TestCompareDocuments_Swagger_ExternalDocs_Removed(t *testing.T) {
|
||||||
@@ -724,6 +726,8 @@ jsonSchemaDialect: https://pb33f.io/schema`
|
|||||||
// compare.
|
// compare.
|
||||||
extChanges := CompareDocuments(&lDoc, &rDoc)
|
extChanges := CompareDocuments(&lDoc, &rDoc)
|
||||||
assert.Nil(t, extChanges)
|
assert.Nil(t, extChanges)
|
||||||
|
assert.NotNil(t, lDoc.GetExternalDocs())
|
||||||
|
assert.Nil(t, lDoc.FindSecurityRequirement("chewy")) // because why not.
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompareDocuments_OpenAPI_BaseProperties_Modified(t *testing.T) {
|
func TestCompareDocuments_OpenAPI_BaseProperties_Modified(t *testing.T) {
|
||||||
@@ -753,3 +757,240 @@ jsonSchemaDialect: https://pb33f.io/schema/changed`
|
|||||||
assert.Equal(t, 3, extChanges.TotalChanges())
|
assert.Equal(t, 3, extChanges.TotalChanges())
|
||||||
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
|
assert.Equal(t, 2, extChanges.TotalBreakingChanges())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCompareDocuments_OpenAPI_AddComponents(t *testing.T) {
|
||||||
|
|
||||||
|
left := `openapi: 3.1`
|
||||||
|
|
||||||
|
right := `openapi: 3.1
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
thing:
|
||||||
|
type: int`
|
||||||
|
|
||||||
|
var lNode, rNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||||
|
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||||
|
|
||||||
|
// have to build docs fully to get access to objects
|
||||||
|
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
|
||||||
|
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
|
||||||
|
|
||||||
|
lDoc, _ := v3.CreateDocument(siLeft)
|
||||||
|
rDoc, _ := v3.CreateDocument(siRight)
|
||||||
|
|
||||||
|
// compare.
|
||||||
|
extChanges := CompareDocuments(lDoc, rDoc)
|
||||||
|
|
||||||
|
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||||
|
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||||
|
assert.Equal(t, PropertyAdded, extChanges.Changes[0].ChangeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareDocuments_OpenAPI_Removed(t *testing.T) {
|
||||||
|
|
||||||
|
left := `openapi: 3.1`
|
||||||
|
|
||||||
|
right := `openapi: 3.1
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
thing:
|
||||||
|
type: int`
|
||||||
|
|
||||||
|
var lNode, rNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||||
|
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||||
|
|
||||||
|
// have to build docs fully to get access to objects
|
||||||
|
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
|
||||||
|
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
|
||||||
|
|
||||||
|
lDoc, _ := v3.CreateDocument(siLeft)
|
||||||
|
rDoc, _ := v3.CreateDocument(siRight)
|
||||||
|
|
||||||
|
// compare.
|
||||||
|
extChanges := CompareDocuments(rDoc, lDoc)
|
||||||
|
|
||||||
|
assert.Equal(t, 1, extChanges.TotalChanges())
|
||||||
|
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||||
|
assert.Equal(t, PropertyRemoved, extChanges.Changes[0].ChangeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareDocuments_OpenAPI_ModifyPaths(t *testing.T) {
|
||||||
|
|
||||||
|
left := `openapi: 3.1
|
||||||
|
paths:
|
||||||
|
/brown/cow:
|
||||||
|
get:
|
||||||
|
description: brown cow
|
||||||
|
/brown/hen:
|
||||||
|
get:
|
||||||
|
description: brown hen`
|
||||||
|
|
||||||
|
right := `openapi: 3.1
|
||||||
|
paths:
|
||||||
|
/brown/cow:
|
||||||
|
get:
|
||||||
|
description: brown cow modified
|
||||||
|
/brown/hen:
|
||||||
|
get:
|
||||||
|
description: brown hen modified`
|
||||||
|
|
||||||
|
var lNode, rNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||||
|
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||||
|
|
||||||
|
// have to build docs fully to get access to objects
|
||||||
|
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
|
||||||
|
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
|
||||||
|
|
||||||
|
lDoc, _ := v3.CreateDocument(siLeft)
|
||||||
|
rDoc, _ := v3.CreateDocument(siRight)
|
||||||
|
|
||||||
|
// compare.
|
||||||
|
extChanges := CompareDocuments(lDoc, rDoc)
|
||||||
|
|
||||||
|
assert.Equal(t, 2, extChanges.TotalChanges())
|
||||||
|
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareDocuments_OpenAPI_Identical_Security(t *testing.T) {
|
||||||
|
|
||||||
|
left := `openapi: 3.1
|
||||||
|
security:
|
||||||
|
- cakes:
|
||||||
|
- chocolate
|
||||||
|
- vanilla
|
||||||
|
- shoes:
|
||||||
|
- white
|
||||||
|
- black`
|
||||||
|
|
||||||
|
right := `openapi: 3.1
|
||||||
|
security:
|
||||||
|
- shoes:
|
||||||
|
- black
|
||||||
|
- white
|
||||||
|
- cakes:
|
||||||
|
- vanilla
|
||||||
|
- chocolate `
|
||||||
|
|
||||||
|
var lNode, rNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||||
|
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||||
|
|
||||||
|
// have to build docs fully to get access to objects
|
||||||
|
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
|
||||||
|
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
|
||||||
|
|
||||||
|
lDoc, _ := v3.CreateDocument(siLeft)
|
||||||
|
rDoc, _ := v3.CreateDocument(siRight)
|
||||||
|
|
||||||
|
// compare.
|
||||||
|
extChanges := CompareDocuments(lDoc, rDoc)
|
||||||
|
assert.Nil(t, extChanges)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareDocuments_OpenAPI_ModifyComponents(t *testing.T) {
|
||||||
|
|
||||||
|
left := `openapi: 3.1
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
athing:
|
||||||
|
description: a schema
|
||||||
|
nothing:
|
||||||
|
description: nothing`
|
||||||
|
|
||||||
|
right := `openapi: 3.1
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
athing:
|
||||||
|
description: a schema that changed
|
||||||
|
nothing:
|
||||||
|
description: nothing with an update`
|
||||||
|
|
||||||
|
var lNode, rNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||||
|
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||||
|
|
||||||
|
// have to build docs fully to get access to objects
|
||||||
|
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
|
||||||
|
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
|
||||||
|
|
||||||
|
lDoc, _ := v3.CreateDocument(siLeft)
|
||||||
|
rDoc, _ := v3.CreateDocument(siRight)
|
||||||
|
|
||||||
|
// compare.
|
||||||
|
extChanges := CompareDocuments(lDoc, rDoc)
|
||||||
|
|
||||||
|
assert.Equal(t, 2, extChanges.TotalChanges())
|
||||||
|
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareDocuments_OpenAPI_ModifyServers(t *testing.T) {
|
||||||
|
|
||||||
|
left := `openapi: 3.1
|
||||||
|
servers:
|
||||||
|
- url: https://pb33f.io
|
||||||
|
- url: https://quobix.com`
|
||||||
|
|
||||||
|
right := `openapi: 3.1
|
||||||
|
servers:
|
||||||
|
- url: https://pb33f.io
|
||||||
|
description: hello!
|
||||||
|
- url: https://api.pb33f.io`
|
||||||
|
|
||||||
|
var lNode, rNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||||
|
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||||
|
|
||||||
|
// have to build docs fully to get access to objects
|
||||||
|
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
|
||||||
|
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
|
||||||
|
|
||||||
|
lDoc, _ := v3.CreateDocument(siLeft)
|
||||||
|
rDoc, _ := v3.CreateDocument(siRight)
|
||||||
|
|
||||||
|
// compare.
|
||||||
|
extChanges := CompareDocuments(lDoc, rDoc)
|
||||||
|
|
||||||
|
assert.Equal(t, 3, extChanges.TotalChanges())
|
||||||
|
assert.Equal(t, 1, extChanges.TotalBreakingChanges())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareDocuments_OpenAPI_ModifyWebhooks(t *testing.T) {
|
||||||
|
|
||||||
|
left := `openapi: 3.1
|
||||||
|
webhooks:
|
||||||
|
bHook:
|
||||||
|
get:
|
||||||
|
description: coffee
|
||||||
|
aHook:
|
||||||
|
get:
|
||||||
|
description: jazz`
|
||||||
|
|
||||||
|
right := `openapi: 3.1
|
||||||
|
webhooks:
|
||||||
|
bHook:
|
||||||
|
get:
|
||||||
|
description: coffee in the morning
|
||||||
|
aHook:
|
||||||
|
get:
|
||||||
|
description: jazz in the evening`
|
||||||
|
|
||||||
|
var lNode, rNode yaml.Node
|
||||||
|
_ = yaml.Unmarshal([]byte(left), &lNode)
|
||||||
|
_ = yaml.Unmarshal([]byte(right), &rNode)
|
||||||
|
|
||||||
|
// have to build docs fully to get access to objects
|
||||||
|
siLeft, _ := datamodel.ExtractSpecInfo([]byte(left))
|
||||||
|
siRight, _ := datamodel.ExtractSpecInfo([]byte(right))
|
||||||
|
|
||||||
|
lDoc, _ := v3.CreateDocument(siLeft)
|
||||||
|
rDoc, _ := v3.CreateDocument(siRight)
|
||||||
|
|
||||||
|
// compare.
|
||||||
|
extChanges := CompareDocuments(lDoc, rDoc)
|
||||||
|
|
||||||
|
assert.Equal(t, 2, extChanges.TotalChanges())
|
||||||
|
assert.Equal(t, 0, extChanges.TotalBreakingChanges())
|
||||||
|
}
|
||||||
|
|||||||
@@ -265,3 +265,59 @@ tags:
|
|||||||
assert.Nil(t, changes)
|
assert.Nil(t, changes)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCompareTags_AddExternalDocs(t *testing.T) {
|
||||||
|
|
||||||
|
left := `openapi: 3.0.1
|
||||||
|
tags:
|
||||||
|
- name: something else`
|
||||||
|
|
||||||
|
right := `openapi: 3.0.1
|
||||||
|
tags:
|
||||||
|
- name: something else
|
||||||
|
externalDocs:
|
||||||
|
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)
|
||||||
|
|
||||||
|
// compare.
|
||||||
|
changes := CompareTags(lDoc.Tags.Value, rDoc.Tags.Value)
|
||||||
|
|
||||||
|
// evaluate.
|
||||||
|
assert.Equal(t, 1, changes.TotalChanges())
|
||||||
|
assert.Equal(t, ObjectAdded, changes.Changes[0].ChangeType)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareTags_RemoveExternalDocs(t *testing.T) {
|
||||||
|
|
||||||
|
left := `openapi: 3.0.1
|
||||||
|
tags:
|
||||||
|
- name: something else`
|
||||||
|
|
||||||
|
right := `openapi: 3.0.1
|
||||||
|
tags:
|
||||||
|
- name: something else
|
||||||
|
externalDocs:
|
||||||
|
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)
|
||||||
|
|
||||||
|
// compare.
|
||||||
|
changes := CompareTags(rDoc.Tags.Value, lDoc.Tags.Value)
|
||||||
|
|
||||||
|
// evaluate.
|
||||||
|
assert.Equal(t, 1, changes.TotalChanges())
|
||||||
|
assert.Equal(t, ObjectRemoved, changes.Changes[0].ChangeType)
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,3 +3,16 @@
|
|||||||
|
|
||||||
package what_changed
|
package what_changed
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
|
"github.com/pb33f/libopenapi/what-changed/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CompareOpenAPIDocuments(original, updated *v3.Document) *model.DocumentChanges {
|
||||||
|
return model.CompareDocuments(original, updated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompareSwaggerDocuments(original, updated *v2.Swagger) *model.DocumentChanges {
|
||||||
|
return model.CompareDocuments(original, updated)
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,3 +2,19 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package what_changed
|
package what_changed
|
||||||
|
|
||||||
|
//func TestCompareOpenAPIDocuments(t *testing.T) {
|
||||||
|
//
|
||||||
|
// original, _ := ioutil.ReadFile("../test_specs/burgershop.openapi.yaml")
|
||||||
|
// modified, _ := ioutil.ReadFile("../test_specs/burgershop.openapi-modified.yaml")
|
||||||
|
// infoOrig, _ := datamodel.ExtractSpecInfo(original)
|
||||||
|
// infoMod, _ := datamodel.ExtractSpecInfo(modified)
|
||||||
|
//
|
||||||
|
// origDoc, _ := v3.CreateDocument(infoOrig)
|
||||||
|
// modDoc, _ := v3.CreateDocument(infoMod)
|
||||||
|
//
|
||||||
|
// changes := CompareOpenAPIDocuments(origDoc, modDoc)
|
||||||
|
//
|
||||||
|
// assert.Nil(t, changes)
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|||||||
Reference in New Issue
Block a user