Tuning parameter exraction for circular ref handling

Lots and lots of variations. means lots of branches to check.

Signed-off-by: quobix <dave@quobix.com>
This commit is contained in:
quobix
2023-11-02 15:04:47 -04:00
parent a8a0e1d47f
commit 713aeecdfa
7 changed files with 370 additions and 68 deletions

View File

@@ -75,7 +75,7 @@ func FindComponent(root *yaml.Node, componentId, absoluteFilePath string, index
Path: friendlySearch,
RemoteLocation: absoluteFilePath,
Index: index,
RequiredRefProperties: extractDefinitionRequiredRefProperties(resNode, map[string][]string{}, fullDef),
RequiredRefProperties: extractDefinitionRequiredRefProperties(resNode, map[string][]string{}, fullDef, index),
}
return ref
}
@@ -174,7 +174,7 @@ func (index *SpecIndex) lookupRolodex(uri []string) *Reference {
IsRemote: true,
RemoteLocation: absoluteFileLocation,
Path: "$",
RequiredRefProperties: extractDefinitionRequiredRefProperties(parsedDocument, map[string][]string{}, absoluteFileLocation),
RequiredRefProperties: extractDefinitionRequiredRefProperties(parsedDocument, map[string][]string{}, absoluteFileLocation, index),
}
return foundRef
} else {

View File

@@ -87,9 +87,30 @@ func (resolver *Resolver) GetResolvingErrors() []*ResolvingError {
return resolver.resolvingErrors
}
// GetCircularErrors returns all circular reference errors found.
func (resolver *Resolver) GetCircularErrors() []*CircularReferenceResult {
return resolver.circularReferences
func (resolver *Resolver) GetCircularReferences() []*CircularReferenceResult {
return resolver.GetSafeCircularReferences()
}
// GetSafeCircularReferences returns all circular reference errors found.
func (resolver *Resolver) GetSafeCircularReferences() []*CircularReferenceResult {
var refs []*CircularReferenceResult
for _, ref := range resolver.circularReferences {
if !ref.IsInfiniteLoop {
refs = append(refs, ref)
}
}
return refs
}
// GetInfiniteCircularReferences returns all circular reference errors found that are infinite / unrecoverable
func (resolver *Resolver) GetInfiniteCircularReferences() []*CircularReferenceResult {
var refs []*CircularReferenceResult
for _, ref := range resolver.circularReferences {
if ref.IsInfiniteLoop {
refs = append(refs, ref)
}
}
return refs
}
// GetPolymorphicCircularErrors returns all circular errors that stem from polymorphism
@@ -339,9 +360,17 @@ func (resolver *Resolver) isInfiniteCircularDependency(ref *Reference, visitedDe
for refDefinition := range ref.RequiredRefProperties {
r, _ := resolver.specIndex.SearchIndexForReference(refDefinition)
if initialRef != nil && initialRef.Definition == r.Definition {
if initialRef != nil && initialRef.FullDefinition == r.FullDefinition {
return true, visitedDefinitions
}
if len(visitedDefinitions) > 0 && ref.FullDefinition == r.FullDefinition {
return true, visitedDefinitions
}
if visitedDefinitions[r.FullDefinition] {
continue
}
visitedDefinitions[r.Definition] = true
ir := initialRef

View File

@@ -75,7 +75,7 @@ func TestResolver_CheckForCircularReferences(t *testing.T) {
assert.Len(t, rolo.GetCaughtErrors(), 3)
assert.Len(t, rolo.GetRootIndex().GetResolver().GetResolvingErrors(), 3)
assert.Len(t, rolo.GetRootIndex().GetResolver().GetCircularErrors(), 3)
assert.Len(t, rolo.GetRootIndex().GetResolver().GetInfiniteCircularReferences(), 3)
}
@@ -107,8 +107,8 @@ components:
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 1)
assert.Len(t, resolver.GetResolvingErrors(), 1) // infinite loop is a resolving error.
assert.Len(t, resolver.GetCircularErrors(), 1)
assert.True(t, resolver.GetCircularErrors()[0].IsArrayResult)
assert.Len(t, resolver.GetInfiniteCircularReferences(), 1)
assert.True(t, resolver.GetInfiniteCircularReferences()[0].IsArrayResult)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
@@ -144,7 +144,7 @@ components:
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 0)
assert.Len(t, resolver.GetResolvingErrors(), 0)
assert.Len(t, resolver.GetCircularErrors(), 0)
assert.Len(t, resolver.GetCircularReferences(), 0)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
@@ -180,7 +180,7 @@ components:
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 0)
assert.Len(t, resolver.GetResolvingErrors(), 0)
assert.Len(t, resolver.GetCircularErrors(), 0)
assert.Len(t, resolver.GetCircularReferences(), 0)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
@@ -216,7 +216,7 @@ components:
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 0)
assert.Len(t, resolver.GetResolvingErrors(), 0)
assert.Len(t, resolver.GetCircularErrors(), 0)
assert.Len(t, resolver.GetCircularReferences(), 0)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
@@ -252,7 +252,7 @@ components:
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 0)
assert.Len(t, resolver.GetResolvingErrors(), 0)
assert.Len(t, resolver.GetCircularErrors(), 0)
assert.Len(t, resolver.GetCircularReferences(), 0)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
@@ -286,8 +286,8 @@ components:
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 0)
assert.Len(t, resolver.GetResolvingErrors(), 0) // not an infinite loop if poly.
assert.Len(t, resolver.GetCircularErrors(), 1)
assert.Equal(t, "anyOf", resolver.GetCircularErrors()[0].PolymorphicType)
assert.Len(t, resolver.GetCircularReferences(), 1)
assert.Equal(t, "anyOf", resolver.GetCircularReferences()[0].PolymorphicType)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
}
@@ -320,9 +320,9 @@ components:
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 0)
assert.Len(t, resolver.GetResolvingErrors(), 0) // not an infinite loop if poly.
assert.Len(t, resolver.GetCircularErrors(), 1)
assert.Equal(t, "allOf", resolver.GetCircularErrors()[0].PolymorphicType)
assert.True(t, resolver.GetCircularErrors()[0].IsPolymorphicResult)
assert.Len(t, resolver.GetCircularReferences(), 1)
assert.Equal(t, "allOf", resolver.GetCircularReferences()[0].PolymorphicType)
assert.True(t, resolver.GetCircularReferences()[0].IsPolymorphicResult)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
}
@@ -595,7 +595,7 @@ func TestResolver_ResolveComponents_MixedRef(t *testing.T) {
index := rolo.GetRootIndex
resolver := index().GetResolver()
assert.Len(t, resolver.GetCircularErrors(), 0)
assert.Len(t, resolver.GetCircularReferences(), 0)
assert.Equal(t, 2, resolver.GetIndexesVisited())
// in v0.8.2 a new check was added when indexing, to prevent re-indexing the same file multiple times.
@@ -778,3 +778,81 @@ func TestResolver_isInfiniteCircularDep_NoRef(t *testing.T) {
assert.False(t, a)
assert.Nil(t, b)
}
func TestResolver_AllowedCircle(t *testing.T) {
d := `openapi: 3.1.0
paths:
/test:
get:
responses:
'200':
description: OK
components:
schemas:
Obj:
type: object
properties:
other:
$ref: '#/components/schemas/Obj2'
Obj2:
type: object
properties:
other:
$ref: '#/components/schemas/Obj'
required:
- other`
var rootNode yaml.Node
_ = yaml.Unmarshal([]byte(d), &rootNode)
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
resolver := NewResolver(idx)
assert.NotNil(t, resolver)
circ := resolver.Resolve()
assert.Len(t, circ, 0)
assert.Len(t, resolver.GetInfiniteCircularReferences(), 0)
assert.Len(t, resolver.GetSafeCircularReferences(), 1)
}
func TestResolver_NotAllowedDeepCircle(t *testing.T) {
d := `openapi: 3.0
components:
schemas:
Three:
description: "test three"
properties:
bester:
"$ref": "#/components/schemas/Seven"
required:
- bester
Seven:
properties:
wow:
"$ref": "#/components/schemas/Three"
required:
- wow`
var rootNode yaml.Node
_ = yaml.Unmarshal([]byte(d), &rootNode)
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
resolver := NewResolver(idx)
assert.NotNil(t, resolver)
circ := resolver.Resolve()
assert.Len(t, circ, 1)
assert.Len(t, resolver.GetInfiniteCircularReferences(), 1)
assert.Len(t, resolver.GetSafeCircularReferences(), 0)
}
/*
*/

View File

@@ -49,20 +49,22 @@ type RolodexFS interface {
// and the ability to resolve references across those file systems. It is used to hold references to external
// files, and the indexes they hold. The rolodex is the master lookup for all references.
type Rolodex struct {
localFS map[string]fs.FS
remoteFS map[string]fs.FS
indexed bool
built bool
manualBuilt bool
resolved bool
circChecked bool
indexConfig *SpecIndexConfig
indexingDuration time.Duration
indexes []*SpecIndex
rootIndex *SpecIndex
rootNode *yaml.Node
caughtErrors []error
ignoredCircularReferences []*CircularReferenceResult
localFS map[string]fs.FS
remoteFS map[string]fs.FS
indexed bool
built bool
manualBuilt bool
resolved bool
circChecked bool
indexConfig *SpecIndexConfig
indexingDuration time.Duration
indexes []*SpecIndex
rootIndex *SpecIndex
rootNode *yaml.Node
caughtErrors []error
safeCircularReferences []*CircularReferenceResult
infiniteCircularReferences []*CircularReferenceResult
ignoredCircularReferences []*CircularReferenceResult
}
// NewRolodex creates a new rolodex with the provided index configuration.
@@ -316,6 +318,8 @@ func (r *Rolodex) CheckForCircularReferences() {
if len(r.rootIndex.resolver.ignoredArrayReferences) > 0 {
r.ignoredCircularReferences = append(r.ignoredCircularReferences, r.rootIndex.resolver.ignoredArrayReferences...)
}
r.safeCircularReferences = append(r.safeCircularReferences, r.rootIndex.resolver.GetSafeCircularReferences()...)
r.infiniteCircularReferences = append(r.infiniteCircularReferences, r.rootIndex.resolver.GetInfiniteCircularReferences()...)
}
r.circChecked = true
}
@@ -334,6 +338,8 @@ func (r *Rolodex) Resolve() {
if len(r.rootIndex.resolver.ignoredArrayReferences) > 0 {
r.ignoredCircularReferences = append(r.ignoredCircularReferences, r.rootIndex.resolver.ignoredArrayReferences...)
}
r.safeCircularReferences = append(r.safeCircularReferences, r.rootIndex.resolver.GetSafeCircularReferences()...)
r.infiniteCircularReferences = append(r.infiniteCircularReferences, r.rootIndex.resolver.GetInfiniteCircularReferences()...)
}
r.resolved = true
}

View File

@@ -352,7 +352,6 @@ components:
rolodex.AddLocalFS(baseDir, fileFS)
err = rolodex.IndexTheRolodex()
assert.Error(t, err)
assert.Equal(t, "infinite circular reference detected: CircleTest: CircleTest -> -> CircleTest [5:7]", err.Error())
assert.Len(t, rolodex.GetCaughtErrors(), 1)
assert.Len(t, rolodex.GetIgnoredCircularReferences(), 0)
}
@@ -1417,7 +1416,9 @@ components:
rolo.CheckForCircularReferences()
assert.Len(t, rolo.GetIgnoredCircularReferences(), 0)
assert.Len(t, rolo.GetCaughtErrors(), 1)
assert.Len(t, rolo.GetRootIndex().GetResolver().GetCircularErrors(), 1)
assert.Len(t, rolo.GetRootIndex().GetResolver().GetInfiniteCircularReferences(), 1)
assert.Len(t, rolo.GetRootIndex().GetResolver().GetSafeCircularReferences(), 0)
}
func TestRolodex_CircularReferencesArrayIgnored(t *testing.T) {

View File

@@ -32,14 +32,14 @@ func (index *SpecIndex) extractDefinitionsAndSchemas(schemasNode *yaml.Node, pat
Node: schema,
Path: fmt.Sprintf("$.components.schemas.%s", name),
ParentNode: schemasNode,
RequiredRefProperties: extractDefinitionRequiredRefProperties(schemasNode, map[string][]string{}, fullDef),
RequiredRefProperties: extractDefinitionRequiredRefProperties(schemasNode, map[string][]string{}, fullDef, index),
}
index.allComponentSchemaDefinitions[def] = ref
}
}
// extractDefinitionRequiredRefProperties goes through the direct properties of a schema and extracts the map of required definitions from within it
func extractDefinitionRequiredRefProperties(schemaNode *yaml.Node, reqRefProps map[string][]string, fulldef string) map[string][]string {
func extractDefinitionRequiredRefProperties(schemaNode *yaml.Node, reqRefProps map[string][]string, fulldef string, idx *SpecIndex) map[string][]string {
if schemaNode == nil {
return reqRefProps
}
@@ -74,7 +74,7 @@ func extractDefinitionRequiredRefProperties(schemaNode *yaml.Node, reqRefProps m
// Check to see if the current property is directly embedded within the current schema, and handle its properties if so
_, paramPropertiesMapNode := utils.FindKeyNodeTop("properties", param.Content)
if paramPropertiesMapNode != nil {
reqRefProps = extractDefinitionRequiredRefProperties(param, reqRefProps, fulldef)
reqRefProps = extractDefinitionRequiredRefProperties(param, reqRefProps, fulldef, idx)
}
// Check to see if the current property is polymorphic, and dive into that model if so
@@ -82,7 +82,7 @@ func extractDefinitionRequiredRefProperties(schemaNode *yaml.Node, reqRefProps m
_, ofNode := utils.FindKeyNodeTop(key, param.Content)
if ofNode != nil {
for _, ofNodeItem := range ofNode.Content {
reqRefProps = extractRequiredReferenceProperties(fulldef, ofNodeItem, name, reqRefProps)
reqRefProps = extractRequiredReferenceProperties(fulldef, idx, ofNodeItem, name, reqRefProps)
}
}
}
@@ -95,19 +95,19 @@ func extractDefinitionRequiredRefProperties(schemaNode *yaml.Node, reqRefProps m
continue
}
reqRefProps = extractRequiredReferenceProperties(fulldef, requiredPropDefNode, requiredPropertyNode.Value, reqRefProps)
reqRefProps = extractRequiredReferenceProperties(fulldef, idx, requiredPropDefNode, requiredPropertyNode.Value, reqRefProps)
}
return reqRefProps
}
// extractRequiredReferenceProperties returns a map of definition names to the property or properties which reference it within a node
func extractRequiredReferenceProperties(fulldef string, requiredPropDefNode *yaml.Node, propName string, reqRefProps map[string][]string) map[string][]string {
isRef, _, _ := utils.IsNodeRefValue(requiredPropDefNode)
func extractRequiredReferenceProperties(fulldef string, idx *SpecIndex, requiredPropDefNode *yaml.Node, propName string, reqRefProps map[string][]string) map[string][]string {
isRef, _, refName := utils.IsNodeRefValue(requiredPropDefNode)
if !isRef {
_, defItems := utils.FindKeyNodeTop("items", requiredPropDefNode.Content)
if defItems != nil {
isRef, _, _ = utils.IsNodeRefValue(defItems)
isRef, _, refName = utils.IsNodeRefValue(defItems)
}
}
@@ -117,28 +117,65 @@ func extractRequiredReferenceProperties(fulldef string, requiredPropDefNode *yam
defPath := fulldef
// explode defpath
exp := strings.Split(fulldef, "#/")
if len(exp) == 2 {
if exp[0] != "" {
if !strings.HasPrefix(exp[0], "http") {
if !filepath.IsAbs(exp[0]) {
abs, _ := filepath.Abs(filepath.Join(filepath.Dir(fulldef), exp[0]))
defPath = fmt.Sprintf("%s#/%s", abs, exp[1])
}
}
}
if strings.HasPrefix(refName, "http") || filepath.IsAbs(refName) {
defPath = refName
} else {
if strings.HasPrefix(exp[0], "http") {
defPath = exp[0]
} else {
exp := strings.Split(fulldef, "#/")
if len(exp) == 2 {
if exp[0] != "" {
if strings.HasPrefix(exp[0], "http") {
u, _ := url.Parse(exp[0])
r := strings.Split(refName, "#/")
if len(r) == 2 {
var abs string
if r[0] == "" {
abs = u.Path
} else {
abs, _ = filepath.Abs(filepath.Join(filepath.Dir(u.Path), r[0]))
}
if filepath.IsAbs(exp[0]) {
defPath = exp[0]
u.Path = abs
u.Fragment = ""
defPath = fmt.Sprintf("%s#/%s", u.String(), r[1])
} else {
u.Path = filepath.Join(filepath.Dir(u.Path), r[0])
u.Fragment = ""
defPath = u.String()
}
} else {
r := strings.Split(refName, "#/")
if len(r) == 2 {
var abs string
if r[0] == "" {
abs, _ = filepath.Abs(exp[0])
} else {
abs, _ = filepath.Abs(filepath.Join(filepath.Dir(exp[0]), r[0]))
}
defPath = fmt.Sprintf("%s#/%s", abs, r[1])
} else {
defPath, _ = filepath.Abs(filepath.Join(filepath.Dir(exp[0]), r[0]))
}
}
} else {
defPath, _ = filepath.Abs(filepath.Join(filepath.Dir(fulldef), exp[0]))
defPath = refName
}
} else {
if strings.HasPrefix(exp[0], "http") {
u, _ := url.Parse(exp[0])
r := strings.Split(refName, "#/")
if len(r) == 2 {
abs, _ := filepath.Abs(filepath.Join(filepath.Dir(u.Path), r[0]))
u.Path = abs
u.Fragment = ""
defPath = fmt.Sprintf("%s#/%s", u.String(), r[1])
} else {
u.Path = filepath.Join(filepath.Dir(u.Path), r[0])
u.Fragment = ""
defPath = u.String()
}
} else {
defPath, _ = filepath.Abs(filepath.Join(filepath.Dir(exp[0]), refName))
}
}
}

View File

@@ -57,7 +57,7 @@ func Test_extractRequiredReferenceProperties(t *testing.T) {
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("the-big.yaml#/cheese/thing",
data := extractRequiredReferenceProperties("the-big.yaml#/cheese/thing", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.NotNil(t, data)
@@ -71,7 +71,7 @@ func Test_extractRequiredReferenceProperties_singleFile(t *testing.T) {
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("dingo-bingo-bango.yaml",
data := extractRequiredReferenceProperties("dingo-bingo-bango.yaml", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.NotNil(t, data)
@@ -85,7 +85,7 @@ func Test_extractRequiredReferenceProperties_http(t *testing.T) {
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("http://dingo-bingo-bango.yaml/camel.yaml",
data := extractRequiredReferenceProperties("http://dingo-bingo-bango.yaml/camel.yaml", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.NotNil(t, data)
@@ -99,12 +99,163 @@ func Test_extractRequiredReferenceProperties_abs(t *testing.T) {
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("/camel.yaml",
data := extractRequiredReferenceProperties("/camel.yaml", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.NotNil(t, data)
}
func Test_extractDefinitionRequiredRefProperties_nil(t *testing.T) {
assert.Nil(t, extractDefinitionRequiredRefProperties(nil, nil, ""))
func Test_extractRequiredReferenceProperties_abs3(t *testing.T) {
d := `$ref: oh/pillow.yaml`
var rootNode yaml.Node
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("/big/fat/camel.yaml#/milk", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.Equal(t, "cakes", props["/big/fat/oh/pillow.yaml"][0])
assert.NotNil(t, data)
}
func Test_extractRequiredReferenceProperties_rel_full(t *testing.T) {
d := `$ref: "#/a/nice/picture/of/cake"`
var rootNode yaml.Node
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("/chalky/milky/camel.yaml#/milk", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.Equal(t, "cakes", props["/chalky/milky/camel.yaml#/a/nice/picture/of/cake"][0])
assert.NotNil(t, data)
}
func Test_extractRequiredReferenceProperties_rel(t *testing.T) {
d := `$ref: oh/camel.yaml#/rum/cake`
var rootNode yaml.Node
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("/camel.yaml#/milk", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.Equal(t, "cakes", props["/oh/camel.yaml#/rum/cake"][0])
assert.NotNil(t, data)
}
func Test_extractRequiredReferenceProperties_abs2(t *testing.T) {
d := `$ref: /oh/my/camel.yaml#/rum/cake`
var rootNode yaml.Node
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("../flannel.yaml#/milk", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.Equal(t, "cakes", props["/oh/my/camel.yaml#/rum/cake"][0])
assert.NotNil(t, data)
}
func Test_extractRequiredReferenceProperties_http_rel(t *testing.T) {
d := `$ref: my/wet/camel.yaml#/rum/cake`
var rootNode yaml.Node
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("http://beer-world.com/lost/in/space.yaml#/vase", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.Equal(t, "cakes", props["http://beer-world.com/lost/in/my/wet/camel.yaml#/rum/cake"][0])
assert.NotNil(t, data)
}
func Test_extractRequiredReferenceProperties_http_rel_nocomponent(t *testing.T) {
d := `$ref: my/wet/camel.yaml`
var rootNode yaml.Node
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("http://beer-world.com/lost/in/space.yaml#/vase", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.Equal(t, "cakes", props["http://beer-world.com/lost/in/my/wet/camel.yaml"][0])
assert.NotNil(t, data)
}
func Test_extractRequiredReferenceProperties_nocomponent(t *testing.T) {
d := `$ref: my/wet/camel.yaml`
var rootNode yaml.Node
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("#/rotund/cakes", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.Equal(t, "cakes", props["my/wet/camel.yaml"][0])
assert.NotNil(t, data)
}
func Test_extractRequiredReferenceProperties_component_http(t *testing.T) {
d := `$ref: go-to-bed.com/no/more/cake.yaml#/lovely/jam`
var rootNode yaml.Node
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("http://bunny-bun-bun.com/no.yaml", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.Equal(t, "cakes", props["http://bunny-bun-bun.com/go-to-bed.com/no/more/cake.yaml#/lovely/jam"][0])
assert.NotNil(t, data)
}
func Test_extractRequiredReferenceProperties_nocomponent_http(t *testing.T) {
d := `$ref: go-to-bed.com/no/more/cake.yaml`
var rootNode yaml.Node
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("http://bunny-bun-bun.com/no.yaml", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.Equal(t, "cakes", props["http://bunny-bun-bun.com/go-to-bed.com/no/more/cake.yaml"][0])
assert.NotNil(t, data)
}
func Test_extractRequiredReferenceProperties_nocomponent_http2(t *testing.T) {
d := `$ref: go-to-bed.com/no/more/cake.yaml`
var rootNode yaml.Node
_ = yaml.Unmarshal([]byte(d), &rootNode)
props := make(map[string][]string)
data := extractRequiredReferenceProperties("/why.yaml", nil,
rootNode.Content[0], "cakes", props)
assert.Len(t, props, 1)
assert.Equal(t, "cakes", props["/go-to-bed.com/no/more/cake.yaml"][0])
assert.NotNil(t, data)
}
func Test_extractDefinitionRequiredRefProperties_nil(t *testing.T) {
assert.Nil(t, extractDefinitionRequiredRefProperties(nil, nil, "", nil))
}