From 3715938ce87371a9f3c2a1a73d55aab55a160471 Mon Sep 17 00:00:00 2001 From: quobix Date: Fri, 1 Dec 2023 17:58:11 -0500 Subject: [PATCH 1/2] fixed resolving issue, not all refs being resolved. This got tucked in somehow, the sequence is what is used by the resolver to replace refs. This fixes an issue in vacuum. Signed-off-by: quobix --- index/extract_refs.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/index/extract_refs.go b/index/extract_refs.go index 5cbf73c..0eaca7b 100644 --- a/index/extract_refs.go +++ b/index/extract_refs.go @@ -562,14 +562,14 @@ func (index *SpecIndex) ExtractComponentsFromRefs(refs []*Reference) []*Referenc if index.allMappedRefs[ref.FullDefinition] == nil { found = append(found, located) index.allMappedRefs[located.FullDefinition] = located - rm := &ReferenceMapped{ - OriginalReference: ref, - Reference: located, - Definition: located.Definition, - FullDefinition: located.FullDefinition, - } - sequence[refIndex] = rm } + rm := &ReferenceMapped{ + OriginalReference: ref, + Reference: located, + Definition: located.Definition, + FullDefinition: located.FullDefinition, + } + sequence[refIndex] = rm index.refLock.Unlock() } else { From 82c9e21df12e613f27d7347233e61670bb59fcdf Mon Sep 17 00:00:00 2001 From: quobix Date: Fri, 1 Dec 2023 18:06:42 -0500 Subject: [PATCH 2/2] fixed tests. Signed-off-by: quobix --- index/resolver_test.go | 1042 +++++++++++------------ index/spec_index_test.go | 1734 +++++++++++++++++++------------------- 2 files changed, 1388 insertions(+), 1388 deletions(-) diff --git a/index/resolver_test.go b/index/resolver_test.go index 731966d..5bfa02f 100644 --- a/index/resolver_test.go +++ b/index/resolver_test.go @@ -1,150 +1,150 @@ package index import ( - "errors" - "fmt" - "github.com/pb33f/libopenapi/datamodel" - "github.com/pb33f/libopenapi/utils" - "github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath" - "net/http" - "net/url" - "os" - "path/filepath" - "testing" + "errors" + "fmt" + "github.com/pb33f/libopenapi/datamodel" + "github.com/pb33f/libopenapi/utils" + "github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath" + "net/http" + "net/url" + "os" + "path/filepath" + "testing" - "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v3" + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" ) func TestNewResolver(t *testing.T) { - assert.Nil(t, NewResolver(nil)) + assert.Nil(t, NewResolver(nil)) } func TestResolvingError_Error(t *testing.T) { - errs := []error{ - &ResolvingError{ - Path: "$.test1", - ErrorRef: errors.New("test1"), - Node: &yaml.Node{ - Line: 1, - Column: 1, - }, - }, - &ResolvingError{ - Path: "$.test2", - ErrorRef: errors.New("test2"), - Node: &yaml.Node{ - Line: 1, - Column: 1, - }, - }, - } + errs := []error{ + &ResolvingError{ + Path: "$.test1", + ErrorRef: errors.New("test1"), + Node: &yaml.Node{ + Line: 1, + Column: 1, + }, + }, + &ResolvingError{ + Path: "$.test2", + ErrorRef: errors.New("test2"), + Node: &yaml.Node{ + Line: 1, + Column: 1, + }, + }, + } - assert.Equal(t, "test1: $.test1 [1:1]", errs[0].Error()) - assert.Equal(t, "test2: $.test2 [1:1]", errs[1].Error()) + assert.Equal(t, "test1: $.test1 [1:1]", errs[0].Error()) + assert.Equal(t, "test2: $.test2 [1:1]", errs[1].Error()) } func TestResolvingError_Error_Index(t *testing.T) { - errs := []error{ - &ResolvingError{ - ErrorRef: errors.Join(&IndexingError{ - Path: "$.test1", - Err: errors.New("test1"), - Node: &yaml.Node{ - Line: 1, - Column: 1, - }, - }), - Node: &yaml.Node{ - Line: 1, - Column: 1, - }, - }, - &ResolvingError{ - ErrorRef: errors.Join(&IndexingError{ - Path: "$.test2", - Err: errors.New("test2"), - Node: &yaml.Node{ - Line: 1, - Column: 1, - }, - }), - Node: &yaml.Node{ - Line: 1, - Column: 1, - }, - }, - } + errs := []error{ + &ResolvingError{ + ErrorRef: errors.Join(&IndexingError{ + Path: "$.test1", + Err: errors.New("test1"), + Node: &yaml.Node{ + Line: 1, + Column: 1, + }, + }), + Node: &yaml.Node{ + Line: 1, + Column: 1, + }, + }, + &ResolvingError{ + ErrorRef: errors.Join(&IndexingError{ + Path: "$.test2", + Err: errors.New("test2"), + Node: &yaml.Node{ + Line: 1, + Column: 1, + }, + }), + Node: &yaml.Node{ + Line: 1, + Column: 1, + }, + }, + } - assert.Equal(t, "test1: $.test1 [1:1]", errs[0].Error()) - assert.Equal(t, "test2: $.test2 [1:1]", errs[1].Error()) + assert.Equal(t, "test1: $.test1 [1:1]", errs[0].Error()) + assert.Equal(t, "test2: $.test2 [1:1]", errs[1].Error()) } func Benchmark_ResolveDocumentStripe(b *testing.B) { - baseDir := "../test_specs/stripe.yaml" - resolveFile, _ := os.ReadFile(baseDir) - var rootNode yaml.Node - _ = yaml.Unmarshal(resolveFile, &rootNode) + baseDir := "../test_specs/stripe.yaml" + resolveFile, _ := os.ReadFile(baseDir) + var rootNode yaml.Node + _ = yaml.Unmarshal(resolveFile, &rootNode) - for n := 0; n < b.N; n++ { + for n := 0; n < b.N; n++ { - cf := CreateOpenAPIIndexConfig() + cf := CreateOpenAPIIndexConfig() - rolo := NewRolodex(cf) - rolo.SetRootNode(&rootNode) + rolo := NewRolodex(cf) + rolo.SetRootNode(&rootNode) - indexedErr := rolo.IndexTheRolodex() - assert.Len(b, utils.UnwrapErrors(indexedErr), 3) + indexedErr := rolo.IndexTheRolodex() + assert.Len(b, utils.UnwrapErrors(indexedErr), 3) - } + } } func TestResolver_ResolveComponents_CircularSpec(t *testing.T) { - circular, _ := os.ReadFile("../test_specs/circular-tests.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(circular, &rootNode) + circular, _ := os.ReadFile("../test_specs/circular-tests.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(circular, &rootNode) - cf := CreateClosedAPIIndexConfig() - cf.AvoidCircularReferenceCheck = true - rolo := NewRolodex(cf) - rolo.SetRootNode(&rootNode) + cf := CreateClosedAPIIndexConfig() + cf.AvoidCircularReferenceCheck = true + rolo := NewRolodex(cf) + rolo.SetRootNode(&rootNode) - indexedErr := rolo.IndexTheRolodex() - assert.NoError(t, indexedErr) + indexedErr := rolo.IndexTheRolodex() + assert.NoError(t, indexedErr) - rolo.Resolve() - assert.Len(t, rolo.GetCaughtErrors(), 3) + rolo.Resolve() + assert.Len(t, rolo.GetCaughtErrors(), 3) - _, err := yaml.Marshal(rolo.GetRootIndex().GetResolver().resolvedRoot) - assert.NoError(t, err) + _, err := yaml.Marshal(rolo.GetRootIndex().GetResolver().resolvedRoot) + assert.NoError(t, err) } func TestResolver_CheckForCircularReferences(t *testing.T) { - circular, _ := os.ReadFile("../test_specs/circular-tests.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(circular, &rootNode) + circular, _ := os.ReadFile("../test_specs/circular-tests.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(circular, &rootNode) - cf := CreateClosedAPIIndexConfig() + cf := CreateClosedAPIIndexConfig() - rolo := NewRolodex(cf) - rolo.SetRootNode(&rootNode) + rolo := NewRolodex(cf) + rolo.SetRootNode(&rootNode) - indexedErr := rolo.IndexTheRolodex() - assert.Error(t, indexedErr) - assert.Len(t, utils.UnwrapErrors(indexedErr), 3) + indexedErr := rolo.IndexTheRolodex() + assert.Error(t, indexedErr) + assert.Len(t, utils.UnwrapErrors(indexedErr), 3) - rolo.CheckForCircularReferences() + rolo.CheckForCircularReferences() - assert.Len(t, rolo.GetCaughtErrors(), 3) - assert.Len(t, rolo.GetRootIndex().GetResolver().GetResolvingErrors(), 3) - assert.Len(t, rolo.GetRootIndex().GetResolver().GetInfiniteCircularReferences(), 3) + assert.Len(t, rolo.GetCaughtErrors(), 3) + assert.Len(t, rolo.GetRootIndex().GetResolver().GetResolvingErrors(), 3) + assert.Len(t, rolo.GetRootIndex().GetResolver().GetInfiniteCircularReferences(), 3) } func TestResolver_CheckForCircularReferences_CatchArray(t *testing.T) { - circular := []byte(`openapi: 3.0.0 + circular := []byte(`openapi: 3.0.0 components: schemas: ProductCategory: @@ -160,26 +160,26 @@ components: required: - "name" - "children"`) - var rootNode yaml.Node - _ = yaml.Unmarshal(circular, &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal(circular, &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - circ := resolver.CheckForCircularReferences() - assert.Len(t, circ, 1) - assert.Len(t, resolver.GetResolvingErrors(), 1) // infinite loop is a resolving error. - assert.Len(t, resolver.GetInfiniteCircularReferences(), 1) - assert.True(t, resolver.GetInfiniteCircularReferences()[0].IsArrayResult) + circ := resolver.CheckForCircularReferences() + assert.Len(t, circ, 1) + assert.Len(t, resolver.GetResolvingErrors(), 1) // infinite loop is a resolving error. + assert.Len(t, resolver.GetInfiniteCircularReferences(), 1) + assert.True(t, resolver.GetInfiniteCircularReferences()[0].IsArrayResult) - _, err := yaml.Marshal(resolver.resolvedRoot) - assert.NoError(t, err) + _, err := yaml.Marshal(resolver.resolvedRoot) + assert.NoError(t, err) } func TestResolver_CheckForCircularReferences_IgnoreArray(t *testing.T) { - circular := []byte(`openapi: 3.0.0 + circular := []byte(`openapi: 3.0.0 components: schemas: ProductCategory: @@ -195,27 +195,27 @@ components: required: - "name" - "children"`) - var rootNode yaml.Node - _ = yaml.Unmarshal(circular, &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal(circular, &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - resolver.IgnoreArrayCircularReferences() + resolver.IgnoreArrayCircularReferences() - circ := resolver.CheckForCircularReferences() - assert.Len(t, circ, 0) - assert.Len(t, resolver.GetResolvingErrors(), 0) - assert.Len(t, resolver.GetCircularReferences(), 0) + circ := resolver.CheckForCircularReferences() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetResolvingErrors(), 0) + assert.Len(t, resolver.GetCircularReferences(), 0) - _, err := yaml.Marshal(resolver.resolvedRoot) - assert.NoError(t, err) + _, err := yaml.Marshal(resolver.resolvedRoot) + assert.NoError(t, err) } func TestResolver_CheckForCircularReferences_IgnorePoly_Any(t *testing.T) { - circular := []byte(`openapi: 3.0.0 + circular := []byte(`openapi: 3.0.0 components: schemas: ProductCategory: @@ -231,27 +231,27 @@ components: required: - "name" - "children"`) - var rootNode yaml.Node - _ = yaml.Unmarshal(circular, &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal(circular, &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - resolver.IgnorePolymorphicCircularReferences() + resolver.IgnorePolymorphicCircularReferences() - circ := resolver.CheckForCircularReferences() - assert.Len(t, circ, 0) - assert.Len(t, resolver.GetResolvingErrors(), 0) - assert.Len(t, resolver.GetCircularReferences(), 0) + circ := resolver.CheckForCircularReferences() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetResolvingErrors(), 0) + assert.Len(t, resolver.GetCircularReferences(), 0) - _, err := yaml.Marshal(resolver.resolvedRoot) - assert.NoError(t, err) + _, err := yaml.Marshal(resolver.resolvedRoot) + assert.NoError(t, err) } func TestResolver_CheckForCircularReferences_IgnorePoly_All(t *testing.T) { - circular := []byte(`openapi: 3.0.0 + circular := []byte(`openapi: 3.0.0 components: schemas: ProductCategory: @@ -267,27 +267,27 @@ components: required: - "name" - "children"`) - var rootNode yaml.Node - _ = yaml.Unmarshal(circular, &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal(circular, &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - resolver.IgnorePolymorphicCircularReferences() + resolver.IgnorePolymorphicCircularReferences() - circ := resolver.CheckForCircularReferences() - assert.Len(t, circ, 0) - assert.Len(t, resolver.GetResolvingErrors(), 0) - assert.Len(t, resolver.GetCircularReferences(), 0) + circ := resolver.CheckForCircularReferences() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetResolvingErrors(), 0) + assert.Len(t, resolver.GetCircularReferences(), 0) - _, err := yaml.Marshal(resolver.resolvedRoot) - assert.NoError(t, err) + _, err := yaml.Marshal(resolver.resolvedRoot) + assert.NoError(t, err) } func TestResolver_CheckForCircularReferences_IgnorePoly_One(t *testing.T) { - circular := []byte(`openapi: 3.0.0 + circular := []byte(`openapi: 3.0.0 components: schemas: ProductCategory: @@ -303,27 +303,27 @@ components: required: - "name" - "children"`) - var rootNode yaml.Node - _ = yaml.Unmarshal(circular, &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal(circular, &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - resolver.IgnorePolymorphicCircularReferences() + resolver.IgnorePolymorphicCircularReferences() - circ := resolver.CheckForCircularReferences() - assert.Len(t, circ, 0) - assert.Len(t, resolver.GetResolvingErrors(), 0) - assert.Len(t, resolver.GetCircularReferences(), 0) + circ := resolver.CheckForCircularReferences() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetResolvingErrors(), 0) + assert.Len(t, resolver.GetCircularReferences(), 0) - _, err := yaml.Marshal(resolver.resolvedRoot) - assert.NoError(t, err) + _, err := yaml.Marshal(resolver.resolvedRoot) + assert.NoError(t, err) } func TestResolver_CheckForCircularReferences_CatchPoly_Any(t *testing.T) { - circular := []byte(`openapi: 3.0.0 + circular := []byte(`openapi: 3.0.0 components: schemas: ProductCategory: @@ -339,25 +339,25 @@ components: required: - "name" - "children"`) - var rootNode yaml.Node - _ = yaml.Unmarshal(circular, &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal(circular, &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - circ := resolver.CheckForCircularReferences() - assert.Len(t, circ, 0) - assert.Len(t, resolver.GetResolvingErrors(), 0) // not an infinite loop if poly. - assert.Len(t, resolver.GetCircularReferences(), 1) - assert.Equal(t, "anyOf", resolver.GetCircularReferences()[0].PolymorphicType) - _, err := yaml.Marshal(resolver.resolvedRoot) - assert.NoError(t, err) + circ := resolver.CheckForCircularReferences() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetResolvingErrors(), 0) // not an infinite loop if poly. + assert.Len(t, resolver.GetCircularReferences(), 1) + assert.Equal(t, "anyOf", resolver.GetCircularReferences()[0].PolymorphicType) + _, err := yaml.Marshal(resolver.resolvedRoot) + assert.NoError(t, err) } func TestResolver_CheckForCircularReferences_CatchPoly_All(t *testing.T) { - circular := []byte(`openapi: 3.0.0 + circular := []byte(`openapi: 3.0.0 components: schemas: ProductCategory: @@ -373,138 +373,138 @@ components: required: - "name" - "children"`) - var rootNode yaml.Node - _ = yaml.Unmarshal(circular, &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal(circular, &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - circ := resolver.CheckForCircularReferences() - assert.Len(t, circ, 0) - assert.Len(t, resolver.GetResolvingErrors(), 0) // not an infinite loop if poly. - 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) + circ := resolver.CheckForCircularReferences() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetResolvingErrors(), 0) // not an infinite loop if poly. + 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) } func TestResolver_CircularReferencesRequiredValid(t *testing.T) { - circular, _ := os.ReadFile("../test_specs/swagger-valid-recursive-model.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(circular, &rootNode) + circular, _ := os.ReadFile("../test_specs/swagger-valid-recursive-model.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(circular, &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - circ := resolver.CheckForCircularReferences() - assert.Len(t, circ, 0) + circ := resolver.CheckForCircularReferences() + assert.Len(t, circ, 0) - _, err := yaml.Marshal(resolver.resolvedRoot) - assert.NoError(t, err) + _, err := yaml.Marshal(resolver.resolvedRoot) + assert.NoError(t, err) } func TestResolver_CircularReferencesRequiredInvalid(t *testing.T) { - circular, _ := os.ReadFile("../test_specs/swagger-invalid-recursive-model.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(circular, &rootNode) + circular, _ := os.ReadFile("../test_specs/swagger-invalid-recursive-model.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(circular, &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - circ := resolver.CheckForCircularReferences() - assert.Len(t, circ, 2) + circ := resolver.CheckForCircularReferences() + assert.Len(t, circ, 2) - _, err := yaml.Marshal(resolver.resolvedRoot) - assert.NoError(t, err) + _, err := yaml.Marshal(resolver.resolvedRoot) + assert.NoError(t, err) } func TestResolver_DeepJourney(t *testing.T) { - var journey []*Reference - for f := 0; f < 200; f++ { - journey = append(journey, nil) - } - idx := NewSpecIndexWithConfig(nil, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.Nil(t, resolver.extractRelatives(nil, nil, nil, nil, journey, false)) + var journey []*Reference + for f := 0; f < 200; f++ { + journey = append(journey, nil) + } + idx := NewSpecIndexWithConfig(nil, CreateClosedAPIIndexConfig()) + resolver := NewResolver(idx) + assert.Nil(t, resolver.extractRelatives(nil, nil, nil, nil, journey, false)) } func TestResolver_ResolveComponents_Stripe_NoRolodex(t *testing.T) { - baseDir := "../test_specs/stripe.yaml" + baseDir := "../test_specs/stripe.yaml" - resolveFile, _ := os.ReadFile(baseDir) + resolveFile, _ := os.ReadFile(baseDir) - var stripeRoot yaml.Node - _ = yaml.Unmarshal(resolveFile, &stripeRoot) + var stripeRoot yaml.Node + _ = yaml.Unmarshal(resolveFile, &stripeRoot) - info, _ := datamodel.ExtractSpecInfoWithDocumentCheck(resolveFile, true) + info, _ := datamodel.ExtractSpecInfoWithDocumentCheck(resolveFile, true) - cf := CreateOpenAPIIndexConfig() - cf.SpecInfo = info + cf := CreateOpenAPIIndexConfig() + cf.SpecInfo = info - idx := NewSpecIndexWithConfig(&stripeRoot, cf) + idx := NewSpecIndexWithConfig(&stripeRoot, cf) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - circ := resolver.CheckForCircularReferences() - assert.Len(t, circ, 2) + circ := resolver.CheckForCircularReferences() + assert.Len(t, circ, 2) - _, err := yaml.Marshal(resolver.resolvedRoot) - assert.NoError(t, err) + _, err := yaml.Marshal(resolver.resolvedRoot) + assert.NoError(t, err) } func TestResolver_ResolveComponents_Stripe(t *testing.T) { - baseDir := "../test_specs/stripe.yaml" + baseDir := "../test_specs/stripe.yaml" - resolveFile, _ := os.ReadFile(baseDir) + resolveFile, _ := os.ReadFile(baseDir) - var stripeRoot yaml.Node - _ = yaml.Unmarshal(resolveFile, &stripeRoot) + var stripeRoot yaml.Node + _ = yaml.Unmarshal(resolveFile, &stripeRoot) - info, _ := datamodel.ExtractSpecInfoWithDocumentCheck(resolveFile, true) + info, _ := datamodel.ExtractSpecInfoWithDocumentCheck(resolveFile, true) - cf := CreateOpenAPIIndexConfig() - cf.SpecInfo = info - cf.AvoidCircularReferenceCheck = true + cf := CreateOpenAPIIndexConfig() + cf.SpecInfo = info + cf.AvoidCircularReferenceCheck = true - rolo := NewRolodex(cf) - rolo.SetRootNode(&stripeRoot) + rolo := NewRolodex(cf) + rolo.SetRootNode(&stripeRoot) - indexedErr := rolo.IndexTheRolodex() - assert.NoError(t, indexedErr) + indexedErr := rolo.IndexTheRolodex() + assert.NoError(t, indexedErr) - // after resolving, the rolodex will have errors. - rolo.Resolve() + // after resolving, the rolodex will have errors. + rolo.Resolve() - assert.Len(t, rolo.GetCaughtErrors(), 2) - assert.Len(t, rolo.GetRootIndex().GetResolver().GetNonPolymorphicCircularErrors(), 2) - assert.Len(t, rolo.GetRootIndex().GetResolver().GetPolymorphicCircularErrors(), 0) + assert.Len(t, rolo.GetCaughtErrors(), 2) + assert.Len(t, rolo.GetRootIndex().GetResolver().GetNonPolymorphicCircularErrors(), 2) + assert.Len(t, rolo.GetRootIndex().GetResolver().GetPolymorphicCircularErrors(), 0) } func TestResolver_ResolveComponents_BurgerShop(t *testing.T) { - mixedref, _ := os.ReadFile("../test_specs/burgershop.openapi.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(mixedref, &rootNode) + mixedref, _ := os.ReadFile("../test_specs/burgershop.openapi.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(mixedref, &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - circ := resolver.Resolve() - assert.Len(t, circ, 0) + circ := resolver.Resolve() + assert.Len(t, circ, 0) } func TestResolver_ResolveComponents_PolyNonCircRef(t *testing.T) { - yml := `paths: + yml := `paths: /hey: get: responses: @@ -524,20 +524,20 @@ components: tea: description: tea` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - circ := resolver.CheckForCircularReferences() - assert.Len(t, circ, 0) + circ := resolver.CheckForCircularReferences() + assert.Len(t, circ, 0) } func TestResolver_ResolveComponents_PolyCircRef(t *testing.T) { - yml := `openapi: 3.1.0 + yml := `openapi: 3.1.0 components: schemas: cheese: @@ -551,24 +551,24 @@ components: tea: description: tea` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - _ = resolver.CheckForCircularReferences() - resolver.circularReferences[0].IsInfiniteLoop = true // override - assert.Len(t, idx.GetCircularReferences(), 1) - assert.Len(t, resolver.GetPolymorphicCircularErrors(), 1) - assert.Equal(t, 2, idx.GetCircularReferences()[0].LoopIndex) + _ = resolver.CheckForCircularReferences() + resolver.circularReferences[0].IsInfiniteLoop = true // override + assert.Len(t, idx.GetCircularReferences(), 1) + assert.Len(t, resolver.GetPolymorphicCircularErrors(), 1) + assert.Equal(t, 2, idx.GetCircularReferences()[0].LoopIndex) } func TestResolver_ResolveComponents_Missing(t *testing.T) { - yml := `paths: + yml := `paths: /hey: get: responses: @@ -587,21 +587,21 @@ components: butter: $ref: 'go home, I am drunk'` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - err := resolver.Resolve() - assert.Len(t, err, 2) - assert.Equal(t, "cannot resolve reference `go home, I am drunk`, it's missing: $go home, I am drunk [18:11]", err[0].Error()) + err := resolver.Resolve() + assert.Len(t, err, 2) + assert.Equal(t, "cannot resolve reference `go home, I am drunk`, it's missing: $go home, I am drunk [18:11]", err[0].Error()) } func TestResolver_ResolveThroughPaths(t *testing.T) { - yml := `paths: + yml := `paths: /pizza/{cake}/{pizza}/pie: parameters: - name: juicy @@ -612,148 +612,148 @@ func TestResolver_ResolveThroughPaths(t *testing.T) { parameters: - $ref: '#/paths/~1pizza~1%7Bcake%7D~1%7Bpizza%7D~1pie/parameters/0'` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - err := resolver.Resolve() - assert.Len(t, err, 0) + err := resolver.Resolve() + assert.Len(t, err, 0) } func TestResolver_ResolveComponents_MixedRef(t *testing.T) { - mixedref, _ := os.ReadFile("../test_specs/mixedref-burgershop.openapi.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(mixedref, &rootNode) + mixedref, _ := os.ReadFile("../test_specs/mixedref-burgershop.openapi.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(mixedref, &rootNode) - // create a test server. - server := test_buildMixedRefServer() - defer server.Close() + // create a test server. + server := test_buildMixedRefServer() + defer server.Close() - // create a new config that allows local and remote to be mixed up. - cf := CreateOpenAPIIndexConfig() - cf.AvoidBuildIndex = true - cf.AllowRemoteLookup = true - cf.AvoidCircularReferenceCheck = true - cf.BasePath = "../test_specs" + // create a new config that allows local and remote to be mixed up. + cf := CreateOpenAPIIndexConfig() + cf.AvoidBuildIndex = true + cf.AllowRemoteLookup = true + cf.AvoidCircularReferenceCheck = true + cf.BasePath = "../test_specs" - // setting this baseURL will override the base - cf.BaseURL, _ = url.Parse(server.URL) + // setting this baseURL will override the base + cf.BaseURL, _ = url.Parse(server.URL) - // create a new rolodex - rolo := NewRolodex(cf) + // create a new rolodex + rolo := NewRolodex(cf) - // set the rolodex root node to the root node of the spec. - rolo.SetRootNode(&rootNode) + // set the rolodex root node to the root node of the spec. + rolo.SetRootNode(&rootNode) - // create a new remote fs and set the config for indexing. - remoteFS, _ := NewRemoteFSWithRootURL(server.URL) - remoteFS.SetIndexConfig(cf) + // create a new remote fs and set the config for indexing. + remoteFS, _ := NewRemoteFSWithRootURL(server.URL) + remoteFS.SetIndexConfig(cf) - // set our remote handler func + // set our remote handler func - c := http.Client{} + c := http.Client{} - remoteFS.RemoteHandlerFunc = c.Get + remoteFS.RemoteHandlerFunc = c.Get - // configure the local filesystem. - fsCfg := LocalFSConfig{ - BaseDirectory: cf.BasePath, - FileFilters: []string{"burgershop.openapi.yaml"}, - DirFS: os.DirFS(cf.BasePath), - } + // configure the local filesystem. + fsCfg := LocalFSConfig{ + BaseDirectory: cf.BasePath, + FileFilters: []string{"burgershop.openapi.yaml"}, + DirFS: os.DirFS(cf.BasePath), + } - // create a new local filesystem. - fileFS, err := NewLocalFSWithConfig(&fsCfg) - assert.NoError(t, err) + // create a new local filesystem. + fileFS, err := NewLocalFSWithConfig(&fsCfg) + assert.NoError(t, err) - // add file systems to the rolodex - rolo.AddLocalFS(cf.BasePath, fileFS) - rolo.AddRemoteFS(server.URL, remoteFS) + // add file systems to the rolodex + rolo.AddLocalFS(cf.BasePath, fileFS) + rolo.AddRemoteFS(server.URL, remoteFS) - // index the rolodex. - indexedErr := rolo.IndexTheRolodex() + // index the rolodex. + indexedErr := rolo.IndexTheRolodex() - assert.NoError(t, indexedErr) + assert.NoError(t, indexedErr) - rolo.Resolve() - index := rolo.GetRootIndex - resolver := index().GetResolver() + rolo.Resolve() + index := rolo.GetRootIndex + resolver := index().GetResolver() - assert.Len(t, resolver.GetCircularReferences(), 0) - assert.Equal(t, 2, resolver.GetIndexesVisited()) + 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. - assert.Equal(t, 6, resolver.GetRelativesSeen()) - assert.Equal(t, 5, resolver.GetJourneysTaken()) - assert.Equal(t, 7, resolver.GetReferenceVisited()) + // in v0.8.2 a new check was added when indexing, to prevent re-indexing the same file multiple times. + assert.Equal(t, 6, resolver.GetRelativesSeen()) + assert.Equal(t, 6, resolver.GetJourneysTaken()) + assert.Equal(t, 8, resolver.GetReferenceVisited()) } func TestResolver_ResolveComponents_k8s(t *testing.T) { - k8s, _ := os.ReadFile("../test_specs/k8s.json") - var rootNode yaml.Node - _ = yaml.Unmarshal(k8s, &rootNode) + k8s, _ := os.ReadFile("../test_specs/k8s.json") + var rootNode yaml.Node + _ = yaml.Unmarshal(k8s, &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + assert.NotNil(t, resolver) - circ := resolver.Resolve() - assert.Len(t, circ, 0) + circ := resolver.Resolve() + assert.Len(t, circ, 0) } // Example of how to resolve the Stripe OpenAPI specification, and check for circular reference errors func ExampleNewResolver() { - // create a yaml.Node reference as a root node. - var rootNode yaml.Node + // create a yaml.Node reference as a root node. + var rootNode yaml.Node - // load in the Stripe OpenAPI spec (lots of polymorphic complexity in here) - stripeBytes, _ := os.ReadFile("../test_specs/stripe.yaml") + // load in the Stripe OpenAPI spec (lots of polymorphic complexity in here) + stripeBytes, _ := os.ReadFile("../test_specs/stripe.yaml") - // unmarshal bytes into our rootNode. - _ = yaml.Unmarshal(stripeBytes, &rootNode) + // unmarshal bytes into our rootNode. + _ = yaml.Unmarshal(stripeBytes, &rootNode) - // create a new spec index (resolver depends on it) - indexConfig := CreateClosedAPIIndexConfig() - idx := NewSpecIndexWithConfig(&rootNode, indexConfig) + // create a new spec index (resolver depends on it) + indexConfig := CreateClosedAPIIndexConfig() + idx := NewSpecIndexWithConfig(&rootNode, indexConfig) - // create a new resolver using the index. - resolver := NewResolver(idx) + // create a new resolver using the index. + resolver := NewResolver(idx) - // resolve the document, if there are circular reference errors, they are returned/ - // WARNING: this is a destructive action and the rootNode will be PERMANENTLY altered and cannot be unresolved - circularErrors := resolver.Resolve() + // resolve the document, if there are circular reference errors, they are returned/ + // WARNING: this is a destructive action and the rootNode will be PERMANENTLY altered and cannot be unresolved + circularErrors := resolver.Resolve() - // The Stripe API has a bunch of circular reference problems, mainly from polymorphism. - // So let's print them out. - // - fmt.Printf("There are %d circular reference errors, %d of them are polymorphic errors, %d are not", - len(circularErrors), len(resolver.GetPolymorphicCircularErrors()), len(resolver.GetNonPolymorphicCircularErrors())) - // Output: There are 2 circular reference errors, 0 of them are polymorphic errors, 2 are not + // The Stripe API has a bunch of circular reference problems, mainly from polymorphism. + // So let's print them out. + // + fmt.Printf("There are %d circular reference errors, %d of them are polymorphic errors, %d are not", + len(circularErrors), len(resolver.GetPolymorphicCircularErrors()), len(resolver.GetNonPolymorphicCircularErrors())) + // Output: There are 2 circular reference errors, 0 of them are polymorphic errors, 2 are not } func ExampleResolvingError() { - re := ResolvingError{ - ErrorRef: errors.New("je suis une erreur"), - Node: &yaml.Node{ - Line: 5, - Column: 21, - }, - Path: "#/definitions/JeSuisUneErreur", - CircularReference: &CircularReferenceResult{}, - } + re := ResolvingError{ + ErrorRef: errors.New("je suis une erreur"), + Node: &yaml.Node{ + Line: 5, + Column: 21, + }, + Path: "#/definitions/JeSuisUneErreur", + CircularReference: &CircularReferenceResult{}, + } - fmt.Printf("%s", re.Error()) - // Output: je suis une erreur: #/definitions/JeSuisUneErreur [5:21] + fmt.Printf("%s", re.Error()) + // Output: je suis une erreur: #/definitions/JeSuisUneErreur [5:21] } func TestDocument_IgnoreArrayCircularReferences(t *testing.T) { - var d = `openapi: 3.1.0 + var d = `openapi: 3.1.0 components: schemas: ProductCategory: @@ -770,24 +770,24 @@ components: - "name" - "children"` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(d), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(d), &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - resolver.IgnoreArrayCircularReferences() - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + resolver.IgnoreArrayCircularReferences() + assert.NotNil(t, resolver) - circ := resolver.Resolve() - assert.Len(t, circ, 0) - assert.Len(t, resolver.GetIgnoredCircularArrayReferences(), 1) + circ := resolver.Resolve() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetIgnoredCircularArrayReferences(), 1) } func TestDocument_IgnorePolyCircularReferences(t *testing.T) { - var d = `openapi: 3.1.0 + var d = `openapi: 3.1.0 components: schemas: ProductCategory: @@ -804,24 +804,24 @@ components: - "name" - "children"` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(d), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(d), &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - resolver.IgnorePolymorphicCircularReferences() - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + resolver.IgnorePolymorphicCircularReferences() + assert.NotNil(t, resolver) - circ := resolver.Resolve() - assert.Len(t, circ, 0) - assert.Len(t, resolver.GetIgnoredCircularPolyReferences(), 1) + circ := resolver.Resolve() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetIgnoredCircularPolyReferences(), 1) } func TestDocument_IgnorePolyCircularReferences_NoArrayForRef(t *testing.T) { - var d = `openapi: 3.1.0 + var d = `openapi: 3.1.0 components: schemas: bingo: @@ -845,31 +845,31 @@ components: - "name" - "children"` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(d), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(d), &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - resolver.IgnorePolymorphicCircularReferences() - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + resolver.IgnorePolymorphicCircularReferences() + assert.NotNil(t, resolver) - circ := resolver.Resolve() - assert.Len(t, circ, 0) - assert.Len(t, resolver.GetIgnoredCircularPolyReferences(), 1) + circ := resolver.Resolve() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetIgnoredCircularPolyReferences(), 1) } func TestResolver_isInfiniteCircularDep_NoRef(t *testing.T) { - resolver := NewResolver(nil) - a, b := resolver.isInfiniteCircularDependency(nil, nil, nil) - assert.False(t, a) - assert.Nil(t, b) + resolver := NewResolver(nil) + a, b := resolver.isInfiniteCircularDependency(nil, nil, nil) + assert.False(t, a) + assert.Nil(t, b) } func TestResolver_AllowedCircle(t *testing.T) { - d := `openapi: 3.1.0 + d := `openapi: 3.1.0 paths: /test: get: @@ -891,24 +891,24 @@ components: required: - other` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(d), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(d), &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + 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) + circ := resolver.Resolve() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetInfiniteCircularReferences(), 0) + assert.Len(t, resolver.GetSafeCircularReferences(), 1) } func TestResolver_AllowedCircle_Array(t *testing.T) { - d := `openapi: 3.1.0 + d := `openapi: 3.1.0 components: schemas: Obj: @@ -928,29 +928,29 @@ components: required: - children` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(d), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(d), &rootNode) - cf := CreateClosedAPIIndexConfig() - cf.IgnoreArrayCircularReferences = true + cf := CreateClosedAPIIndexConfig() + cf.IgnoreArrayCircularReferences = true - idx := NewSpecIndexWithConfig(&rootNode, cf) + idx := NewSpecIndexWithConfig(&rootNode, cf) - resolver := NewResolver(idx) - resolver.IgnoreArrayCircularReferences() - assert.NotNil(t, resolver) + resolver := NewResolver(idx) + resolver.IgnoreArrayCircularReferences() + assert.NotNil(t, resolver) - circ := resolver.Resolve() - assert.Len(t, circ, 0) - assert.Len(t, resolver.GetInfiniteCircularReferences(), 0) - assert.Len(t, resolver.GetSafeCircularReferences(), 0) - assert.Len(t, resolver.GetIgnoredCircularArrayReferences(), 1) + circ := resolver.Resolve() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetInfiniteCircularReferences(), 0) + assert.Len(t, resolver.GetSafeCircularReferences(), 0) + assert.Len(t, resolver.GetIgnoredCircularArrayReferences(), 1) } func TestResolver_NotAllowedDeepCircle(t *testing.T) { - d := `openapi: 3.0 + d := `openapi: 3.0 components: schemas: Three: @@ -967,62 +967,62 @@ components: required: - wow` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(d), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(d), &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) - resolver := NewResolver(idx) - assert.NotNil(t, resolver) + 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) + circ := resolver.Resolve() + assert.Len(t, circ, 1) + assert.Len(t, resolver.GetInfiniteCircularReferences(), 1) + assert.Len(t, resolver.GetSafeCircularReferences(), 0) } func TestLocateRefEnd_WithResolve(t *testing.T) { - yml, _ := os.ReadFile("../../test_specs/first.yaml") - var bsn yaml.Node - _ = yaml.Unmarshal(yml, &bsn) + yml, _ := os.ReadFile("../../test_specs/first.yaml") + var bsn yaml.Node + _ = yaml.Unmarshal(yml, &bsn) - cf := CreateOpenAPIIndexConfig() - cf.BasePath = "../test_specs" + cf := CreateOpenAPIIndexConfig() + cf.BasePath = "../test_specs" - localFSConfig := &LocalFSConfig{ - BaseDirectory: cf.BasePath, - FileFilters: []string{"first.yaml", "second.yaml", "third.yaml", "fourth.yaml"}, - DirFS: os.DirFS(cf.BasePath), - } - localFs, _ := NewLocalFSWithConfig(localFSConfig) - rolo := NewRolodex(cf) - rolo.AddLocalFS(cf.BasePath, localFs) - rolo.SetRootNode(&bsn) - rolo.IndexTheRolodex() + localFSConfig := &LocalFSConfig{ + BaseDirectory: cf.BasePath, + FileFilters: []string{"first.yaml", "second.yaml", "third.yaml", "fourth.yaml"}, + DirFS: os.DirFS(cf.BasePath), + } + localFs, _ := NewLocalFSWithConfig(localFSConfig) + rolo := NewRolodex(cf) + rolo.AddLocalFS(cf.BasePath, localFs) + rolo.SetRootNode(&bsn) + rolo.IndexTheRolodex() - wd, _ := os.Getwd() - cp, _ := filepath.Abs(filepath.Join(wd, "../test_specs/third.yaml")) - third := localFs.GetFiles()[cp] - refs := third.GetIndex().GetMappedReferences() - fullDef := fmt.Sprintf("%s#/properties/property/properties/statistics", cp) - ref := refs[fullDef] + wd, _ := os.Getwd() + cp, _ := filepath.Abs(filepath.Join(wd, "../test_specs/third.yaml")) + third := localFs.GetFiles()[cp] + refs := third.GetIndex().GetMappedReferences() + fullDef := fmt.Sprintf("%s#/properties/property/properties/statistics", cp) + ref := refs[fullDef] - assert.Equal(t, "statistics", ref.Name) - isRef, _, _ := utils.IsNodeRefValue(ref.Node) - assert.True(t, isRef) + assert.Equal(t, "statistics", ref.Name) + isRef, _, _ := utils.IsNodeRefValue(ref.Node) + assert.True(t, isRef) - // resolve the stack, it should convert the ref to a node. - rolo.Resolve() + // resolve the stack, it should convert the ref to a node. + rolo.Resolve() - isRef, _, _ = utils.IsNodeRefValue(ref.Node) - assert.False(t, isRef) + isRef, _, _ = utils.IsNodeRefValue(ref.Node) + assert.False(t, isRef) } func TestResolveDoc_Issue195(t *testing.T) { - spec := `openapi: 3.0.1 + spec := `openapi: 3.0.1 info: title: Some Example! paths: @@ -1035,58 +1035,58 @@ paths: schema: "$ref": https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.yaml#/components/schemas/Error` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(spec), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(spec), &rootNode) - // create an index config - config := CreateOpenAPIIndexConfig() + // create an index config + config := CreateOpenAPIIndexConfig() - // the rolodex will automatically try and check for circular references, you don't want to do this - // if you're resolving the spec, as the node tree is marked as 'seen' and you won't be able to resolve - // correctly. - config.AvoidCircularReferenceCheck = true + // the rolodex will automatically try and check for circular references, you don't want to do this + // if you're resolving the spec, as the node tree is marked as 'seen' and you won't be able to resolve + // correctly. + config.AvoidCircularReferenceCheck = true - // new in 0.13+ is the ability to add remote and local file systems to the index - // requires a new part, the rolodex. It holds all the indexes and knows where to find - // every reference across local and remote files. - rolodex := NewRolodex(config) + // new in 0.13+ is the ability to add remote and local file systems to the index + // requires a new part, the rolodex. It holds all the indexes and knows where to find + // every reference across local and remote files. + rolodex := NewRolodex(config) - // add a new remote file system. - remoteFS, _ := NewRemoteFSWithConfig(config) + // add a new remote file system. + remoteFS, _ := NewRemoteFSWithConfig(config) - // add the remote file system to the rolodex - rolodex.AddRemoteFS("", remoteFS) + // add the remote file system to the rolodex + rolodex.AddRemoteFS("", remoteFS) - // set the root node of the rolodex, this is your spec. - rolodex.SetRootNode(&rootNode) + // set the root node of the rolodex, this is your spec. + rolodex.SetRootNode(&rootNode) - // index the rolodex - indexingError := rolodex.IndexTheRolodex() - if indexingError != nil { - panic(indexingError) - } + // index the rolodex + indexingError := rolodex.IndexTheRolodex() + if indexingError != nil { + panic(indexingError) + } - // resolve the rolodex - rolodex.Resolve() + // resolve the rolodex + rolodex.Resolve() - // there should be no errors at this point - resolvingErrors := rolodex.GetCaughtErrors() - if resolvingErrors != nil { - panic(resolvingErrors) - } + // there should be no errors at this point + resolvingErrors := rolodex.GetCaughtErrors() + if resolvingErrors != nil { + panic(resolvingErrors) + } - // perform some lookups. - var nodes []*yaml.Node + // perform some lookups. + var nodes []*yaml.Node - // pull out schema type - path, _ := yamlpath.NewPath("$.paths./pet/findByStatus.get.responses.default.content['application/json'].schema.type") - nodes, _ = path.Find(&rootNode) - assert.Equal(t, nodes[0].Value, "object") + // pull out schema type + path, _ := yamlpath.NewPath("$.paths./pet/findByStatus.get.responses.default.content['application/json'].schema.type") + nodes, _ = path.Find(&rootNode) + assert.Equal(t, nodes[0].Value, "object") - // pull out required array - path, _ = yamlpath.NewPath("$.paths./pet/findByStatus.get.responses.default.content['application/json'].schema.required") - nodes, _ = path.Find(&rootNode) - assert.Equal(t, nodes[0].Content[0].Value, "code") - assert.Equal(t, nodes[0].Content[1].Value, "message") + // pull out required array + path, _ = yamlpath.NewPath("$.paths./pet/findByStatus.get.responses.default.content['application/json'].schema.required") + nodes, _ = path.Find(&rootNode) + assert.Equal(t, nodes[0].Content[0].Value, "code") + assert.Equal(t, nodes[0].Content[1].Value, "message") } diff --git a/index/spec_index_test.go b/index/spec_index_test.go index 0f6e4e1..17914e5 100644 --- a/index/spec_index_test.go +++ b/index/spec_index_test.go @@ -4,611 +4,611 @@ package index import ( - "bytes" - "fmt" - "github.com/pb33f/libopenapi/utils" - "golang.org/x/sync/syncmap" - "log" - "log/slog" - "net/http" - "net/http/httptest" - "net/url" - "os" - "os/exec" - "path/filepath" - "testing" - "time" + "bytes" + "fmt" + "github.com/pb33f/libopenapi/utils" + "golang.org/x/sync/syncmap" + "log" + "log/slog" + "net/http" + "net/http/httptest" + "net/url" + "os" + "os/exec" + "path/filepath" + "testing" + "time" - "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v3" + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" ) func TestSpecIndex_GetCache(t *testing.T) { - petstore, _ := os.ReadFile("../test_specs/petstorev3.json") - var rootNode yaml.Node - _ = yaml.Unmarshal(petstore, &rootNode) + petstore, _ := os.ReadFile("../test_specs/petstorev3.json") + var rootNode yaml.Node + _ = yaml.Unmarshal(petstore, &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - extCache := index.GetCache() - assert.NotNil(t, extCache) - extCache.Store("test", "test") - loaded, ok := extCache.Load("test") - assert.Equal(t, "test", loaded) - assert.True(t, ok) + extCache := index.GetCache() + assert.NotNil(t, extCache) + extCache.Store("test", "test") + loaded, ok := extCache.Load("test") + assert.Equal(t, "test", loaded) + assert.True(t, ok) - // create a new cache - newCache := new(syncmap.Map) - index.SetCache(newCache) + // create a new cache + newCache := new(syncmap.Map) + index.SetCache(newCache) - // check that the cache has been set. - assert.Equal(t, newCache, index.GetCache()) + // check that the cache has been set. + assert.Equal(t, newCache, index.GetCache()) - // add an item to the new cache and check it exists - newCache.Store("test2", "test2") - loaded, ok = newCache.Load("test2") - assert.Equal(t, "test2", loaded) - assert.True(t, ok) + // add an item to the new cache and check it exists + newCache.Store("test2", "test2") + loaded, ok = newCache.Load("test2") + assert.Equal(t, "test2", loaded) + assert.True(t, ok) - // now check that the new item in the new cache does not exist in the old cache. - loaded, ok = extCache.Load("test2") - assert.Nil(t, loaded) - assert.False(t, ok) + // now check that the new item in the new cache does not exist in the old cache. + loaded, ok = extCache.Load("test2") + assert.Nil(t, loaded) + assert.False(t, ok) } func TestSpecIndex_ExtractRefsStripe(t *testing.T) { - stripe, _ := os.ReadFile("../test_specs/stripe.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(stripe, &rootNode) + stripe, _ := os.ReadFile("../test_specs/stripe.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(stripe, &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Equal(t, 626, len(index.allRefs)) - assert.Equal(t, 871, len(index.allMappedRefs)) - combined := index.GetAllCombinedReferences() - assert.Equal(t, 871, len(combined)) + assert.Equal(t, 626, len(index.allRefs)) + assert.Equal(t, 871, len(index.allMappedRefs)) + combined := index.GetAllCombinedReferences() + assert.Equal(t, 871, len(combined)) - assert.Equal(t, len(index.rawSequencedRefs), 2712) - assert.Equal(t, 336, index.pathCount) - assert.Equal(t, 494, index.operationCount) - assert.Equal(t, 871, index.schemaCount) - assert.Equal(t, 0, index.globalTagsCount) - assert.Equal(t, 0, index.globalLinksCount) - assert.Equal(t, 0, index.componentParamCount) - assert.Equal(t, 162, index.operationParamCount) - assert.Equal(t, 102, index.componentsInlineParamDuplicateCount) - assert.Equal(t, 60, index.componentsInlineParamUniqueCount) - assert.Equal(t, 2579, index.enumCount) - assert.Equal(t, len(index.GetAllEnums()), 2579) - assert.Len(t, index.GetPolyAllOfReferences(), 0) - assert.Len(t, index.GetPolyOneOfReferences(), 315) - assert.Len(t, index.GetPolyAnyOfReferences(), 708) - assert.Len(t, index.GetAllReferenceSchemas(), 2712) - assert.NotNil(t, index.GetRootServersNode()) - assert.Len(t, index.GetAllRootServers(), 1) - assert.Equal(t, "", index.GetSpecAbsolutePath()) - assert.NotNil(t, index.GetLogger()) + assert.Equal(t, len(index.rawSequencedRefs), 2712) + assert.Equal(t, 336, index.pathCount) + assert.Equal(t, 494, index.operationCount) + assert.Equal(t, 871, index.schemaCount) + assert.Equal(t, 0, index.globalTagsCount) + assert.Equal(t, 0, index.globalLinksCount) + assert.Equal(t, 0, index.componentParamCount) + assert.Equal(t, 162, index.operationParamCount) + assert.Equal(t, 102, index.componentsInlineParamDuplicateCount) + assert.Equal(t, 60, index.componentsInlineParamUniqueCount) + assert.Equal(t, 2579, index.enumCount) + assert.Equal(t, len(index.GetAllEnums()), 2579) + assert.Len(t, index.GetPolyAllOfReferences(), 0) + assert.Len(t, index.GetPolyOneOfReferences(), 315) + assert.Len(t, index.GetPolyAnyOfReferences(), 708) + assert.Len(t, index.GetAllReferenceSchemas(), 2712) + assert.NotNil(t, index.GetRootServersNode()) + assert.Len(t, index.GetAllRootServers(), 1) + assert.Equal(t, "", index.GetSpecAbsolutePath()) + assert.NotNil(t, index.GetLogger()) - // not required, but flip the circular result switch on and off. - assert.False(t, index.AllowCircularReferenceResolving()) - index.SetAllowCircularReferenceResolving(true) - assert.True(t, index.AllowCircularReferenceResolving()) + // not required, but flip the circular result switch on and off. + assert.False(t, index.AllowCircularReferenceResolving()) + index.SetAllowCircularReferenceResolving(true) + assert.True(t, index.AllowCircularReferenceResolving()) - // simulate setting of circular references, also pointless but needed for coverage. - assert.Nil(t, index.GetCircularReferences()) - index.SetCircularReferences([]*CircularReferenceResult{new(CircularReferenceResult)}) - assert.Len(t, index.GetCircularReferences(), 1) + // simulate setting of circular references, also pointless but needed for coverage. + assert.Nil(t, index.GetCircularReferences()) + index.SetCircularReferences([]*CircularReferenceResult{new(CircularReferenceResult)}) + assert.Len(t, index.GetCircularReferences(), 1) - assert.Equal(t, 871, len(index.GetRefsByLine())) - assert.Equal(t, 2712, len(index.GetLinesWithReferences()), 1972) - assert.Equal(t, 0, len(index.GetAllExternalDocuments())) + assert.Equal(t, 871, len(index.GetRefsByLine())) + assert.Equal(t, 2712, len(index.GetLinesWithReferences()), 1972) + assert.Equal(t, 0, len(index.GetAllExternalDocuments())) } func TestSpecIndex_Asana(t *testing.T) { - asana, _ := os.ReadFile("../test_specs/asana.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(asana, &rootNode) + asana, _ := os.ReadFile("../test_specs/asana.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(asana, &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Len(t, index.allRefs, 152) - assert.Len(t, index.allMappedRefs, 171) - combined := index.GetAllCombinedReferences() - assert.Equal(t, 171, len(combined)) - assert.Equal(t, 118, index.pathCount) - assert.Equal(t, 152, index.operationCount) - assert.Equal(t, 135, index.schemaCount) - assert.Equal(t, 26, index.globalTagsCount) - assert.Equal(t, 0, index.globalLinksCount) - assert.Equal(t, 30, index.componentParamCount) - assert.Equal(t, 107, index.operationParamCount) - assert.Equal(t, 8, index.componentsInlineParamDuplicateCount) - assert.Equal(t, 69, index.componentsInlineParamUniqueCount) + assert.Len(t, index.allRefs, 152) + assert.Len(t, index.allMappedRefs, 171) + combined := index.GetAllCombinedReferences() + assert.Equal(t, 171, len(combined)) + assert.Equal(t, 118, index.pathCount) + assert.Equal(t, 152, index.operationCount) + assert.Equal(t, 135, index.schemaCount) + assert.Equal(t, 26, index.globalTagsCount) + assert.Equal(t, 0, index.globalLinksCount) + assert.Equal(t, 30, index.componentParamCount) + assert.Equal(t, 107, index.operationParamCount) + assert.Equal(t, 8, index.componentsInlineParamDuplicateCount) + assert.Equal(t, 69, index.componentsInlineParamUniqueCount) } func TestSpecIndex_DigitalOcean(t *testing.T) { - do, _ := os.ReadFile("../test_specs/digitalocean.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(do, &rootNode) + do, _ := os.ReadFile("../test_specs/digitalocean.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(do, &rootNode) - location := "https://raw.githubusercontent.com/digitalocean/openapi/main/specification" - baseURL, _ := url.Parse(location) + location := "https://raw.githubusercontent.com/digitalocean/openapi/main/specification" + baseURL, _ := url.Parse(location) - // create a new config that allows remote lookups. - cf := &SpecIndexConfig{} - cf.AvoidBuildIndex = true - cf.AllowRemoteLookup = true - cf.AvoidCircularReferenceCheck = true - cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ - Level: slog.LevelError, - })) + // create a new config that allows remote lookups. + cf := &SpecIndexConfig{} + cf.AvoidBuildIndex = true + cf.AllowRemoteLookup = true + cf.AvoidCircularReferenceCheck = true + cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelError, + })) - // setting this baseURL will override the base - cf.BaseURL = baseURL + // setting this baseURL will override the base + cf.BaseURL = baseURL - // create a new rolodex - rolo := NewRolodex(cf) + // create a new rolodex + rolo := NewRolodex(cf) - // set the rolodex root node to the root node of the spec. - rolo.SetRootNode(&rootNode) + // set the rolodex root node to the root node of the spec. + rolo.SetRootNode(&rootNode) - // create a new remote fs and set the config for indexing. - remoteFS, _ := NewRemoteFSWithConfig(cf) + // create a new remote fs and set the config for indexing. + remoteFS, _ := NewRemoteFSWithConfig(cf) - // create a handler that uses an env variable to capture any GITHUB_TOKEN in the OS ENV - // and inject it into the request header, so this does not fail when running lots of local tests. - if os.Getenv("GH_PAT") != "" { - fmt.Println("GH_PAT found, setting remote handler func") - client := &http.Client{ - Timeout: time.Second * 120, - } - remoteFS.SetRemoteHandlerFunc(func(url string) (*http.Response, error) { - request, _ := http.NewRequest(http.MethodGet, url, nil) - request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", os.Getenv("GH_PAT"))) - return client.Do(request) - }) - } + // create a handler that uses an env variable to capture any GITHUB_TOKEN in the OS ENV + // and inject it into the request header, so this does not fail when running lots of local tests. + if os.Getenv("GH_PAT") != "" { + fmt.Println("GH_PAT found, setting remote handler func") + client := &http.Client{ + Timeout: time.Second * 120, + } + remoteFS.SetRemoteHandlerFunc(func(url string) (*http.Response, error) { + request, _ := http.NewRequest(http.MethodGet, url, nil) + request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", os.Getenv("GH_PAT"))) + return client.Do(request) + }) + } - // add remote filesystem - rolo.AddRemoteFS(location, remoteFS) + // add remote filesystem + rolo.AddRemoteFS(location, remoteFS) - // index the rolodex. - indexedErr := rolo.IndexTheRolodex() - assert.NoError(t, indexedErr) + // index the rolodex. + indexedErr := rolo.IndexTheRolodex() + assert.NoError(t, indexedErr) - // get all the files! - files := remoteFS.GetFiles() - fileLen := len(files) - assert.Equal(t, 1646, fileLen) - assert.Len(t, remoteFS.GetErrors(), 0) + // get all the files! + files := remoteFS.GetFiles() + fileLen := len(files) + assert.Equal(t, 1646, fileLen) + assert.Len(t, remoteFS.GetErrors(), 0) - // check circular references - rolo.CheckForCircularReferences() - assert.Len(t, rolo.GetCaughtErrors(), 0) - assert.Len(t, rolo.GetIgnoredCircularReferences(), 0) + // check circular references + rolo.CheckForCircularReferences() + assert.Len(t, rolo.GetCaughtErrors(), 0) + assert.Len(t, rolo.GetIgnoredCircularReferences(), 0) } func TestSpecIndex_DigitalOcean_FullCheckoutLocalResolve(t *testing.T) { - // this is a full checkout of the digitalocean API repo. - tmp, _ := os.MkdirTemp("", "openapi") - cmd := exec.Command("git", "clone", "https://github.com/digitalocean/openapi", tmp) - defer os.RemoveAll(filepath.Join(tmp, "openapi")) + // this is a full checkout of the digitalocean API repo. + tmp, _ := os.MkdirTemp("", "openapi") + cmd := exec.Command("git", "clone", "https://github.com/digitalocean/openapi", tmp) + defer os.RemoveAll(filepath.Join(tmp, "openapi")) - err := cmd.Run() - if err != nil { - log.Fatalf("cmd.Run() failed with %s\n", err) - } + err := cmd.Run() + if err != nil { + log.Fatalf("cmd.Run() failed with %s\n", err) + } - spec, _ := filepath.Abs(filepath.Join(tmp, "specification", "DigitalOcean-public.v2.yaml")) - doLocal, _ := os.ReadFile(spec) + spec, _ := filepath.Abs(filepath.Join(tmp, "specification", "DigitalOcean-public.v2.yaml")) + doLocal, _ := os.ReadFile(spec) - var rootNode yaml.Node - _ = yaml.Unmarshal(doLocal, &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal(doLocal, &rootNode) - basePath := filepath.Join(tmp, "specification") + basePath := filepath.Join(tmp, "specification") - // create a new config that allows local and remote to be mixed up. - cf := CreateOpenAPIIndexConfig() - cf.AllowRemoteLookup = true - cf.AvoidCircularReferenceCheck = true - cf.BasePath = basePath - cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ - Level: slog.LevelError, - })) + // create a new config that allows local and remote to be mixed up. + cf := CreateOpenAPIIndexConfig() + cf.AllowRemoteLookup = true + cf.AvoidCircularReferenceCheck = true + cf.BasePath = basePath + cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelError, + })) - // create a new rolodex - rolo := NewRolodex(cf) + // create a new rolodex + rolo := NewRolodex(cf) - // set the rolodex root node to the root node of the spec. - rolo.SetRootNode(&rootNode) + // set the rolodex root node to the root node of the spec. + rolo.SetRootNode(&rootNode) - // configure the local filesystem. - fsCfg := LocalFSConfig{ - BaseDirectory: cf.BasePath, - DirFS: os.DirFS(cf.BasePath), - Logger: cf.Logger, - } + // configure the local filesystem. + fsCfg := LocalFSConfig{ + BaseDirectory: cf.BasePath, + DirFS: os.DirFS(cf.BasePath), + Logger: cf.Logger, + } - // create a new local filesystem. - fileFS, fsErr := NewLocalFSWithConfig(&fsCfg) - assert.NoError(t, fsErr) + // create a new local filesystem. + fileFS, fsErr := NewLocalFSWithConfig(&fsCfg) + assert.NoError(t, fsErr) - files := fileFS.GetFiles() - fileLen := len(files) + files := fileFS.GetFiles() + fileLen := len(files) - assert.Equal(t, 1696, fileLen) + assert.Equal(t, 1699, fileLen) - rolo.AddLocalFS(basePath, fileFS) + rolo.AddLocalFS(basePath, fileFS) - rErr := rolo.IndexTheRolodex() + rErr := rolo.IndexTheRolodex() - assert.NoError(t, rErr) + assert.NoError(t, rErr) - index := rolo.GetRootIndex() + index := rolo.GetRootIndex() - assert.NotNil(t, index) + assert.NotNil(t, index) - assert.Len(t, index.GetMappedReferencesSequenced(), 300) - assert.Len(t, index.GetMappedReferences(), 300) - assert.Len(t, fileFS.GetErrors(), 0) + assert.Len(t, index.GetMappedReferencesSequenced(), 301) + assert.Len(t, index.GetMappedReferences(), 301) + assert.Len(t, fileFS.GetErrors(), 0) - // check circular references - rolo.CheckForCircularReferences() - assert.Len(t, rolo.GetCaughtErrors(), 0) - assert.Len(t, rolo.GetIgnoredCircularReferences(), 0) + // check circular references + rolo.CheckForCircularReferences() + assert.Len(t, rolo.GetCaughtErrors(), 0) + assert.Len(t, rolo.GetIgnoredCircularReferences(), 0) - assert.Equal(t, int64(1330184), rolo.RolodexFileSize()) - assert.Equal(t, "1.27 MB", rolo.RolodexFileSizeAsString()) - assert.Equal(t, 1696, rolo.RolodexTotalFiles()) + assert.Equal(t, int64(1333243), rolo.RolodexFileSize()) + assert.Equal(t, "1.27 MB", rolo.RolodexFileSizeAsString()) + assert.Equal(t, 1699, rolo.RolodexTotalFiles()) } func TestSpecIndex_DigitalOcean_FullCheckoutLocalResolve_RecursiveLookup(t *testing.T) { - // this is a full checkout of the digitalocean API repo. - tmp, _ := os.MkdirTemp("", "openapi") - cmd := exec.Command("git", "clone", "https://github.com/digitalocean/openapi", tmp) - defer os.RemoveAll(filepath.Join(tmp, "openapi")) + // this is a full checkout of the digitalocean API repo. + tmp, _ := os.MkdirTemp("", "openapi") + cmd := exec.Command("git", "clone", "https://github.com/digitalocean/openapi", tmp) + defer os.RemoveAll(filepath.Join(tmp, "openapi")) - err := cmd.Run() - if err != nil { - log.Fatalf("cmd.Run() failed with %s\n", err) - } + err := cmd.Run() + if err != nil { + log.Fatalf("cmd.Run() failed with %s\n", err) + } - spec, _ := filepath.Abs(filepath.Join(tmp, "specification", "DigitalOcean-public.v2.yaml")) - doLocal, _ := os.ReadFile(spec) + spec, _ := filepath.Abs(filepath.Join(tmp, "specification", "DigitalOcean-public.v2.yaml")) + doLocal, _ := os.ReadFile(spec) - var rootNode yaml.Node - _ = yaml.Unmarshal(doLocal, &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal(doLocal, &rootNode) - basePath := filepath.Join(tmp, "specification") + basePath := filepath.Join(tmp, "specification") - // create a new config that allows local and remote to be mixed up. - cf := CreateOpenAPIIndexConfig() - cf.AllowRemoteLookup = true - cf.AvoidCircularReferenceCheck = true - cf.BasePath = basePath - cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ - Level: slog.LevelError, - })) + // create a new config that allows local and remote to be mixed up. + cf := CreateOpenAPIIndexConfig() + cf.AllowRemoteLookup = true + cf.AvoidCircularReferenceCheck = true + cf.BasePath = basePath + cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelError, + })) - // create a new rolodex - rolo := NewRolodex(cf) + // create a new rolodex + rolo := NewRolodex(cf) - // set the rolodex root node to the root node of the spec. - rolo.SetRootNode(&rootNode) + // set the rolodex root node to the root node of the spec. + rolo.SetRootNode(&rootNode) - // configure the local filesystem. - fsCfg := LocalFSConfig{ - BaseDirectory: cf.BasePath, - IndexConfig: cf, - Logger: cf.Logger, - } + // configure the local filesystem. + fsCfg := LocalFSConfig{ + BaseDirectory: cf.BasePath, + IndexConfig: cf, + Logger: cf.Logger, + } - // create a new local filesystem. - fileFS, fsErr := NewLocalFSWithConfig(&fsCfg) - assert.NoError(t, fsErr) + // create a new local filesystem. + fileFS, fsErr := NewLocalFSWithConfig(&fsCfg) + assert.NoError(t, fsErr) - rolo.AddLocalFS(basePath, fileFS) + rolo.AddLocalFS(basePath, fileFS) - rErr := rolo.IndexTheRolodex() - files := fileFS.GetFiles() - fileLen := len(files) + rErr := rolo.IndexTheRolodex() + files := fileFS.GetFiles() + fileLen := len(files) - assert.Equal(t, 1682, fileLen) + assert.Equal(t, 1685, fileLen) - assert.NoError(t, rErr) + assert.NoError(t, rErr) - index := rolo.GetRootIndex() + index := rolo.GetRootIndex() - assert.NotNil(t, index) + assert.NotNil(t, index) - assert.Len(t, index.GetMappedReferencesSequenced(), 300) - assert.Len(t, index.GetMappedReferences(), 300) - assert.Len(t, fileFS.GetErrors(), 0) + assert.Len(t, index.GetMappedReferencesSequenced(), 301) + assert.Len(t, index.GetMappedReferences(), 301) + assert.Len(t, fileFS.GetErrors(), 0) - // check circular references - rolo.CheckForCircularReferences() - assert.Len(t, rolo.GetCaughtErrors(), 0) - assert.Len(t, rolo.GetIgnoredCircularReferences(), 0) + // check circular references + rolo.CheckForCircularReferences() + assert.Len(t, rolo.GetCaughtErrors(), 0) + assert.Len(t, rolo.GetIgnoredCircularReferences(), 0) - assert.Equal(t, int64(1270079), rolo.RolodexFileSize()) - assert.Equal(t, "1.21 MB", rolo.RolodexFileSizeAsString()) - assert.Equal(t, 1682, rolo.RolodexTotalFiles()) + assert.Equal(t, int64(1273069), rolo.RolodexFileSize()) + assert.Equal(t, "1.21 MB", rolo.RolodexFileSizeAsString()) + assert.Equal(t, 1685, rolo.RolodexTotalFiles()) } func TestSpecIndex_DigitalOcean_LookupsNotAllowed(t *testing.T) { - do, _ := os.ReadFile("../test_specs/digitalocean.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(do, &rootNode) + do, _ := os.ReadFile("../test_specs/digitalocean.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(do, &rootNode) - location := "https://raw.githubusercontent.com/digitalocean/openapi/main/specification" - baseURL, _ := url.Parse(location) + location := "https://raw.githubusercontent.com/digitalocean/openapi/main/specification" + baseURL, _ := url.Parse(location) - // create a new config that does not allow remote lookups. - cf := &SpecIndexConfig{} - cf.AvoidBuildIndex = true - cf.AvoidCircularReferenceCheck = true - var op []byte - buf := bytes.NewBuffer(op) - cf.Logger = slog.New(slog.NewJSONHandler(buf, &slog.HandlerOptions{ - Level: slog.LevelError, - })) + // create a new config that does not allow remote lookups. + cf := &SpecIndexConfig{} + cf.AvoidBuildIndex = true + cf.AvoidCircularReferenceCheck = true + var op []byte + buf := bytes.NewBuffer(op) + cf.Logger = slog.New(slog.NewJSONHandler(buf, &slog.HandlerOptions{ + Level: slog.LevelError, + })) - // setting this baseURL will override the base - cf.BaseURL = baseURL + // setting this baseURL will override the base + cf.BaseURL = baseURL - // create a new rolodex - rolo := NewRolodex(cf) + // create a new rolodex + rolo := NewRolodex(cf) - // set the rolodex root node to the root node of the spec. - rolo.SetRootNode(&rootNode) + // set the rolodex root node to the root node of the spec. + rolo.SetRootNode(&rootNode) - // create a new remote fs and set the config for indexing. - remoteFS, _ := NewRemoteFSWithConfig(cf) + // create a new remote fs and set the config for indexing. + remoteFS, _ := NewRemoteFSWithConfig(cf) - // add remote filesystem - rolo.AddRemoteFS(location, remoteFS) + // add remote filesystem + rolo.AddRemoteFS(location, remoteFS) - // index the rolodex. - indexedErr := rolo.IndexTheRolodex() - assert.Error(t, indexedErr) - assert.Len(t, utils.UnwrapErrors(indexedErr), 291) + // index the rolodex. + indexedErr := rolo.IndexTheRolodex() + assert.Error(t, indexedErr) + assert.Len(t, utils.UnwrapErrors(indexedErr), 291) - index := rolo.GetRootIndex() + index := rolo.GetRootIndex() - files := remoteFS.GetFiles() - fileLen := len(files) - assert.Equal(t, 0, fileLen) - assert.Len(t, remoteFS.GetErrors(), 0) + files := remoteFS.GetFiles() + fileLen := len(files) + assert.Equal(t, 0, fileLen) + assert.Len(t, remoteFS.GetErrors(), 0) - // no lookups allowed, bits have not been set, so there should just be a bunch of errors. - assert.True(t, len(index.GetReferenceIndexErrors()) > 0) + // no lookups allowed, bits have not been set, so there should just be a bunch of errors. + assert.True(t, len(index.GetReferenceIndexErrors()) > 0) } func TestSpecIndex_BaseURLError(t *testing.T) { - do, _ := os.ReadFile("../test_specs/digitalocean.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(do, &rootNode) + do, _ := os.ReadFile("../test_specs/digitalocean.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(do, &rootNode) - location := "https://githerbsandcoffeeandcode.com/fresh/herbs/for/you" // not gonna work bro. - baseURL, _ := url.Parse(location) + location := "https://githerbsandcoffeeandcode.com/fresh/herbs/for/you" // not gonna work bro. + baseURL, _ := url.Parse(location) - // create a new config that allows remote lookups. - cf := &SpecIndexConfig{} - cf.AvoidBuildIndex = true - cf.AllowRemoteLookup = true - cf.AvoidCircularReferenceCheck = true - var op []byte - buf := bytes.NewBuffer(op) - cf.Logger = slog.New(slog.NewJSONHandler(buf, &slog.HandlerOptions{ - Level: slog.LevelError, - })) + // create a new config that allows remote lookups. + cf := &SpecIndexConfig{} + cf.AvoidBuildIndex = true + cf.AllowRemoteLookup = true + cf.AvoidCircularReferenceCheck = true + var op []byte + buf := bytes.NewBuffer(op) + cf.Logger = slog.New(slog.NewJSONHandler(buf, &slog.HandlerOptions{ + Level: slog.LevelError, + })) - // setting this baseURL will override the base - cf.BaseURL = baseURL + // setting this baseURL will override the base + cf.BaseURL = baseURL - // create a new rolodex - rolo := NewRolodex(cf) + // create a new rolodex + rolo := NewRolodex(cf) - // set the rolodex root node to the root node of the spec. - rolo.SetRootNode(&rootNode) + // set the rolodex root node to the root node of the spec. + rolo.SetRootNode(&rootNode) - // create a new remote fs and set the config for indexing. - remoteFS, _ := NewRemoteFSWithConfig(cf) + // create a new remote fs and set the config for indexing. + remoteFS, _ := NewRemoteFSWithConfig(cf) - // add remote filesystem - rolo.AddRemoteFS(location, remoteFS) + // add remote filesystem + rolo.AddRemoteFS(location, remoteFS) - // index the rolodex. - indexedErr := rolo.IndexTheRolodex() - assert.Error(t, indexedErr) - assert.Len(t, utils.UnwrapErrors(indexedErr), 291) + // index the rolodex. + indexedErr := rolo.IndexTheRolodex() + assert.Error(t, indexedErr) + assert.Len(t, utils.UnwrapErrors(indexedErr), 291) - files := remoteFS.GetFiles() - fileLen := len(files) - assert.Equal(t, 0, fileLen) - assert.GreaterOrEqual(t, len(remoteFS.GetErrors()), 200) + files := remoteFS.GetFiles() + fileLen := len(files) + assert.Equal(t, 0, fileLen) + assert.GreaterOrEqual(t, len(remoteFS.GetErrors()), 200) } func TestSpecIndex_k8s(t *testing.T) { - asana, _ := os.ReadFile("../test_specs/k8s.json") - var rootNode yaml.Node - _ = yaml.Unmarshal(asana, &rootNode) + asana, _ := os.ReadFile("../test_specs/k8s.json") + var rootNode yaml.Node + _ = yaml.Unmarshal(asana, &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Len(t, index.allRefs, 558) - assert.Equal(t, 563, len(index.allMappedRefs)) - combined := index.GetAllCombinedReferences() - assert.Equal(t, 563, len(combined)) - assert.Equal(t, 436, index.pathCount) - assert.Equal(t, 853, index.operationCount) - assert.Equal(t, 563, index.schemaCount) - assert.Equal(t, 0, index.globalTagsCount) - assert.Equal(t, 58, index.operationTagsCount) - assert.Equal(t, 0, index.globalLinksCount) - assert.Equal(t, 0, index.componentParamCount) - assert.Equal(t, 36, index.operationParamCount) - assert.Equal(t, 26, index.componentsInlineParamDuplicateCount) - assert.Equal(t, 10, index.componentsInlineParamUniqueCount) - assert.Equal(t, 58, index.GetTotalTagsCount()) - assert.Equal(t, 2524, index.GetRawReferenceCount()) + assert.Len(t, index.allRefs, 558) + assert.Equal(t, 563, len(index.allMappedRefs)) + combined := index.GetAllCombinedReferences() + assert.Equal(t, 563, len(combined)) + assert.Equal(t, 436, index.pathCount) + assert.Equal(t, 853, index.operationCount) + assert.Equal(t, 563, index.schemaCount) + assert.Equal(t, 0, index.globalTagsCount) + assert.Equal(t, 58, index.operationTagsCount) + assert.Equal(t, 0, index.globalLinksCount) + assert.Equal(t, 0, index.componentParamCount) + assert.Equal(t, 36, index.operationParamCount) + assert.Equal(t, 26, index.componentsInlineParamDuplicateCount) + assert.Equal(t, 10, index.componentsInlineParamUniqueCount) + assert.Equal(t, 58, index.GetTotalTagsCount()) + assert.Equal(t, 2524, index.GetRawReferenceCount()) } func TestSpecIndex_PetstoreV2(t *testing.T) { - asana, _ := os.ReadFile("../test_specs/petstorev2.json") - var rootNode yaml.Node - _ = yaml.Unmarshal(asana, &rootNode) + asana, _ := os.ReadFile("../test_specs/petstorev2.json") + var rootNode yaml.Node + _ = yaml.Unmarshal(asana, &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Len(t, index.allRefs, 6) - assert.Len(t, index.allMappedRefs, 6) - assert.Equal(t, 14, index.pathCount) - assert.Equal(t, 20, index.operationCount) - assert.Equal(t, 6, index.schemaCount) - assert.Equal(t, 3, index.globalTagsCount) - assert.Equal(t, 3, index.operationTagsCount) - assert.Equal(t, 0, index.globalLinksCount) - assert.Equal(t, 1, index.componentParamCount) - assert.Equal(t, 1, index.GetComponentParameterCount()) - assert.Equal(t, 11, index.operationParamCount) - assert.Equal(t, 5, index.componentsInlineParamDuplicateCount) - assert.Equal(t, 6, index.componentsInlineParamUniqueCount) - assert.Equal(t, 3, index.GetTotalTagsCount()) - assert.Equal(t, 2, len(index.GetSecurityRequirementReferences())) + assert.Len(t, index.allRefs, 6) + assert.Len(t, index.allMappedRefs, 6) + assert.Equal(t, 14, index.pathCount) + assert.Equal(t, 20, index.operationCount) + assert.Equal(t, 6, index.schemaCount) + assert.Equal(t, 3, index.globalTagsCount) + assert.Equal(t, 3, index.operationTagsCount) + assert.Equal(t, 0, index.globalLinksCount) + assert.Equal(t, 1, index.componentParamCount) + assert.Equal(t, 1, index.GetComponentParameterCount()) + assert.Equal(t, 11, index.operationParamCount) + assert.Equal(t, 5, index.componentsInlineParamDuplicateCount) + assert.Equal(t, 6, index.componentsInlineParamUniqueCount) + assert.Equal(t, 3, index.GetTotalTagsCount()) + assert.Equal(t, 2, len(index.GetSecurityRequirementReferences())) } func TestSpecIndex_XSOAR(t *testing.T) { - xsoar, _ := os.ReadFile("../test_specs/xsoar.json") - var rootNode yaml.Node - _ = yaml.Unmarshal(xsoar, &rootNode) + xsoar, _ := os.ReadFile("../test_specs/xsoar.json") + var rootNode yaml.Node + _ = yaml.Unmarshal(xsoar, &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Len(t, index.allRefs, 209) - assert.Equal(t, 85, index.pathCount) - assert.Equal(t, 88, index.operationCount) - assert.Equal(t, 245, index.schemaCount) - assert.Equal(t, 207, len(index.allMappedRefs)) - assert.Equal(t, 0, index.globalTagsCount) - assert.Equal(t, 0, index.operationTagsCount) - assert.Equal(t, 0, index.globalLinksCount) - assert.Len(t, index.GetRootSecurityReferences(), 1) - assert.NotNil(t, index.GetRootSecurityNode()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + assert.Len(t, index.allRefs, 209) + assert.Equal(t, 85, index.pathCount) + assert.Equal(t, 88, index.operationCount) + assert.Equal(t, 245, index.schemaCount) + assert.Equal(t, 207, len(index.allMappedRefs)) + assert.Equal(t, 0, index.globalTagsCount) + assert.Equal(t, 0, index.operationTagsCount) + assert.Equal(t, 0, index.globalLinksCount) + assert.Len(t, index.GetRootSecurityReferences(), 1) + assert.NotNil(t, index.GetRootSecurityNode()) } func TestSpecIndex_PetstoreV3(t *testing.T) { - petstore, _ := os.ReadFile("../test_specs/petstorev3.json") - var rootNode yaml.Node - _ = yaml.Unmarshal(petstore, &rootNode) + petstore, _ := os.ReadFile("../test_specs/petstorev3.json") + var rootNode yaml.Node + _ = yaml.Unmarshal(petstore, &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Len(t, index.allRefs, 7) - assert.Len(t, index.allMappedRefs, 7) - assert.Equal(t, 13, index.pathCount) - assert.Equal(t, 19, index.operationCount) - assert.Equal(t, 8, index.schemaCount) - assert.Equal(t, 3, index.globalTagsCount) - assert.Equal(t, 3, index.operationTagsCount) - assert.Equal(t, 0, index.globalLinksCount) - assert.Equal(t, 0, index.componentParamCount) - assert.Equal(t, 9, index.operationParamCount) - assert.Equal(t, 4, index.componentsInlineParamDuplicateCount) - assert.Equal(t, 5, index.componentsInlineParamUniqueCount) - assert.Equal(t, 3, index.GetTotalTagsCount()) - assert.Equal(t, 90, index.GetAllDescriptionsCount()) - assert.Equal(t, 19, index.GetAllSummariesCount()) - assert.Len(t, index.GetAllDescriptions(), 90) - assert.Len(t, index.GetAllSummaries(), 19) + assert.Len(t, index.allRefs, 7) + assert.Len(t, index.allMappedRefs, 7) + assert.Equal(t, 13, index.pathCount) + assert.Equal(t, 19, index.operationCount) + assert.Equal(t, 8, index.schemaCount) + assert.Equal(t, 3, index.globalTagsCount) + assert.Equal(t, 3, index.operationTagsCount) + assert.Equal(t, 0, index.globalLinksCount) + assert.Equal(t, 0, index.componentParamCount) + assert.Equal(t, 9, index.operationParamCount) + assert.Equal(t, 4, index.componentsInlineParamDuplicateCount) + assert.Equal(t, 5, index.componentsInlineParamUniqueCount) + assert.Equal(t, 3, index.GetTotalTagsCount()) + assert.Equal(t, 90, index.GetAllDescriptionsCount()) + assert.Equal(t, 19, index.GetAllSummariesCount()) + assert.Len(t, index.GetAllDescriptions(), 90) + assert.Len(t, index.GetAllSummaries(), 19) - index.SetAbsolutePath("/rooty/rootster") - assert.Equal(t, "/rooty/rootster", index.GetSpecAbsolutePath()) + index.SetAbsolutePath("/rooty/rootster") + assert.Equal(t, "/rooty/rootster", index.GetSpecAbsolutePath()) } var mappedRefs = 15 func TestSpecIndex_BurgerShop(t *testing.T) { - burgershop, _ := os.ReadFile("../test_specs/burgershop.openapi.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(burgershop, &rootNode) + burgershop, _ := os.ReadFile("../test_specs/burgershop.openapi.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(burgershop, &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Len(t, index.allRefs, mappedRefs) - assert.Len(t, index.allMappedRefs, mappedRefs) - assert.Equal(t, mappedRefs, len(index.GetMappedReferences())) - assert.Equal(t, mappedRefs, len(index.GetMappedReferencesSequenced())) + assert.Len(t, index.allRefs, mappedRefs) + assert.Len(t, index.allMappedRefs, mappedRefs) + assert.Equal(t, mappedRefs, len(index.GetMappedReferences())) + assert.Equal(t, mappedRefs+1, len(index.GetMappedReferencesSequenced())) - assert.Equal(t, 6, index.pathCount) - assert.Equal(t, 6, index.GetPathCount()) + assert.Equal(t, 6, index.pathCount) + assert.Equal(t, 6, index.GetPathCount()) - assert.Equal(t, 6, len(index.GetAllComponentSchemas())) - assert.Equal(t, 56, len(index.GetAllSchemas())) + assert.Equal(t, 6, len(index.GetAllComponentSchemas())) + assert.Equal(t, 56, len(index.GetAllSchemas())) - assert.Equal(t, 34, len(index.GetAllSequencedReferences())) - assert.NotNil(t, index.GetSchemasNode()) - assert.NotNil(t, index.GetParametersNode()) + assert.Equal(t, 34, len(index.GetAllSequencedReferences())) + assert.NotNil(t, index.GetSchemasNode()) + assert.NotNil(t, index.GetParametersNode()) - assert.Equal(t, 5, index.operationCount) - assert.Equal(t, 5, index.GetOperationCount()) + assert.Equal(t, 5, index.operationCount) + assert.Equal(t, 5, index.GetOperationCount()) - assert.Equal(t, 6, index.schemaCount) - assert.Equal(t, 6, index.GetComponentSchemaCount()) + assert.Equal(t, 6, index.schemaCount) + assert.Equal(t, 6, index.GetComponentSchemaCount()) - assert.Equal(t, 2, index.globalTagsCount) - assert.Equal(t, 2, index.GetGlobalTagsCount()) - assert.Equal(t, 2, index.GetTotalTagsCount()) + assert.Equal(t, 2, index.globalTagsCount) + assert.Equal(t, 2, index.GetGlobalTagsCount()) + assert.Equal(t, 2, index.GetTotalTagsCount()) - assert.Equal(t, 2, index.operationTagsCount) - assert.Equal(t, 2, index.GetOperationTagsCount()) + assert.Equal(t, 2, index.operationTagsCount) + assert.Equal(t, 2, index.GetOperationTagsCount()) - assert.Equal(t, 3, index.globalLinksCount) - assert.Equal(t, 3, index.GetGlobalLinksCount()) + assert.Equal(t, 3, index.globalLinksCount) + assert.Equal(t, 3, index.GetGlobalLinksCount()) - assert.Equal(t, 1, index.globalCallbacksCount) - assert.Equal(t, 1, index.GetGlobalCallbacksCount()) + assert.Equal(t, 1, index.globalCallbacksCount) + assert.Equal(t, 1, index.GetGlobalCallbacksCount()) - assert.Equal(t, 2, index.componentParamCount) - assert.Equal(t, 2, index.GetComponentParameterCount()) + assert.Equal(t, 2, index.componentParamCount) + assert.Equal(t, 2, index.GetComponentParameterCount()) - assert.Equal(t, 4, index.operationParamCount) - assert.Equal(t, 4, index.GetOperationsParameterCount()) + assert.Equal(t, 4, index.operationParamCount) + assert.Equal(t, 4, index.GetOperationsParameterCount()) - assert.Equal(t, 0, index.componentsInlineParamDuplicateCount) - assert.Equal(t, 0, index.GetInlineDuplicateParamCount()) + assert.Equal(t, 0, index.componentsInlineParamDuplicateCount) + assert.Equal(t, 0, index.GetInlineDuplicateParamCount()) - assert.Equal(t, 2, index.componentsInlineParamUniqueCount) - assert.Equal(t, 2, index.GetInlineUniqueParamCount()) + assert.Equal(t, 2, index.componentsInlineParamUniqueCount) + assert.Equal(t, 2, index.GetInlineUniqueParamCount()) - assert.Equal(t, 1, len(index.GetAllRequestBodies())) - assert.NotNil(t, index.GetRootNode()) - assert.NotNil(t, index.GetGlobalTagsNode()) - assert.NotNil(t, index.GetPathsNode()) - assert.NotNil(t, index.GetDiscoveredReferences()) - assert.Equal(t, 1, len(index.GetPolyReferences())) - assert.NotNil(t, index.GetOperationParameterReferences()) - assert.Equal(t, 3, len(index.GetAllSecuritySchemes())) - assert.Equal(t, 2, len(index.GetAllParameters())) - assert.Equal(t, 1, len(index.GetAllResponses())) - assert.Equal(t, 2, len(index.GetInlineOperationDuplicateParameters())) - assert.Equal(t, 0, len(index.GetReferencesWithSiblings())) - assert.Equal(t, mappedRefs, len(index.GetAllReferences())) - assert.Equal(t, 0, len(index.GetOperationParametersIndexErrors())) - assert.Equal(t, 5, len(index.GetAllPaths())) - assert.Equal(t, 5, len(index.GetOperationTags())) - assert.Equal(t, 3, len(index.GetAllParametersFromOperations())) + assert.Equal(t, 1, len(index.GetAllRequestBodies())) + assert.NotNil(t, index.GetRootNode()) + assert.NotNil(t, index.GetGlobalTagsNode()) + assert.NotNil(t, index.GetPathsNode()) + assert.NotNil(t, index.GetDiscoveredReferences()) + assert.Equal(t, 1, len(index.GetPolyReferences())) + assert.NotNil(t, index.GetOperationParameterReferences()) + assert.Equal(t, 3, len(index.GetAllSecuritySchemes())) + assert.Equal(t, 2, len(index.GetAllParameters())) + assert.Equal(t, 1, len(index.GetAllResponses())) + assert.Equal(t, 2, len(index.GetInlineOperationDuplicateParameters())) + assert.Equal(t, 0, len(index.GetReferencesWithSiblings())) + assert.Equal(t, mappedRefs, len(index.GetAllReferences())) + assert.Equal(t, 0, len(index.GetOperationParametersIndexErrors())) + assert.Equal(t, 5, len(index.GetAllPaths())) + assert.Equal(t, 5, len(index.GetOperationTags())) + assert.Equal(t, 3, len(index.GetAllParametersFromOperations())) } func TestSpecIndex_GetAllParametersFromOperations(t *testing.T) { - yml := `openapi: 3.0.0 + yml := `openapi: 3.0.0 servers: - url: http://localhost:8080 paths: @@ -624,47 +624,47 @@ paths: schema: type: string` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Equal(t, 1, len(index.GetAllParametersFromOperations())) - assert.Equal(t, 1, len(index.GetOperationParametersIndexErrors())) + assert.Equal(t, 1, len(index.GetAllParametersFromOperations())) + assert.Equal(t, 1, len(index.GetOperationParametersIndexErrors())) } func TestSpecIndex_BurgerShop_AllTheComponents(t *testing.T) { - burgershop, _ := os.ReadFile("../test_specs/all-the-components.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(burgershop, &rootNode) + burgershop, _ := os.ReadFile("../test_specs/all-the-components.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(burgershop, &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Equal(t, 1, len(index.GetAllHeaders())) - assert.Equal(t, 1, len(index.GetAllLinks())) - assert.Equal(t, 1, len(index.GetAllCallbacks())) - assert.Equal(t, 1, len(index.GetAllExamples())) - assert.Equal(t, 1, len(index.GetAllResponses())) - assert.Equal(t, 2, len(index.GetAllRootServers())) - assert.Equal(t, 2, len(index.GetAllOperationsServers())) + assert.Equal(t, 1, len(index.GetAllHeaders())) + assert.Equal(t, 1, len(index.GetAllLinks())) + assert.Equal(t, 1, len(index.GetAllCallbacks())) + assert.Equal(t, 1, len(index.GetAllExamples())) + assert.Equal(t, 1, len(index.GetAllResponses())) + assert.Equal(t, 2, len(index.GetAllRootServers())) + assert.Equal(t, 2, len(index.GetAllOperationsServers())) } func TestSpecIndex_SwaggerResponses(t *testing.T) { - yml := `swagger: 2.0 + yml := `swagger: 2.0 responses: niceResponse: description: hi` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Equal(t, 1, len(index.GetAllResponses())) + assert.Equal(t, 1, len(index.GetAllResponses())) } func TestSpecIndex_NoNameParam(t *testing.T) { - yml := `paths: + yml := `paths: /users/{id}: parameters: - in: path @@ -676,178 +676,178 @@ func TestSpecIndex_NoNameParam(t *testing.T) { name: id - in: query` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Equal(t, 2, len(index.GetOperationParametersIndexErrors())) + assert.Equal(t, 2, len(index.GetOperationParametersIndexErrors())) } func TestSpecIndex_NoRoot(t *testing.T) { - index := NewSpecIndex(nil) - refs := index.ExtractRefs(nil, nil, nil, 0, false, "") - docs := index.ExtractExternalDocuments(nil) - assert.Nil(t, docs) - assert.Nil(t, refs) - assert.Nil(t, index.FindComponent("nothing")) - assert.Equal(t, -1, index.GetOperationCount()) - assert.Equal(t, -1, index.GetPathCount()) - assert.Equal(t, -1, index.GetGlobalTagsCount()) - assert.Equal(t, -1, index.GetOperationTagsCount()) - assert.Equal(t, -1, index.GetTotalTagsCount()) - assert.Equal(t, -1, index.GetOperationsParameterCount()) - assert.Equal(t, -1, index.GetComponentParameterCount()) - assert.Equal(t, -1, index.GetComponentSchemaCount()) - assert.Equal(t, -1, index.GetGlobalLinksCount()) + index := NewSpecIndex(nil) + refs := index.ExtractRefs(nil, nil, nil, 0, false, "") + docs := index.ExtractExternalDocuments(nil) + assert.Nil(t, docs) + assert.Nil(t, refs) + assert.Nil(t, index.FindComponent("nothing")) + assert.Equal(t, -1, index.GetOperationCount()) + assert.Equal(t, -1, index.GetPathCount()) + assert.Equal(t, -1, index.GetGlobalTagsCount()) + assert.Equal(t, -1, index.GetOperationTagsCount()) + assert.Equal(t, -1, index.GetTotalTagsCount()) + assert.Equal(t, -1, index.GetOperationsParameterCount()) + assert.Equal(t, -1, index.GetComponentParameterCount()) + assert.Equal(t, -1, index.GetComponentSchemaCount()) + assert.Equal(t, -1, index.GetGlobalLinksCount()) } func test_buildMixedRefServer() *httptest.Server { - bs, _ := os.ReadFile("../test_specs/burgershop.openapi.yaml") - return httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - rw.Header().Set("Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT") - _, _ = rw.Write(bs) + bs, _ := os.ReadFile("../test_specs/burgershop.openapi.yaml") + return httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + rw.Header().Set("Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT") + _, _ = rw.Write(bs) - })) + })) } func TestSpecIndex_BurgerShopMixedRef(t *testing.T) { - // create a test server. - server := test_buildMixedRefServer() - defer server.Close() + // create a test server. + server := test_buildMixedRefServer() + defer server.Close() - // create a new config that allows local and remote to be mixed up. - cf := CreateOpenAPIIndexConfig() - cf.AvoidBuildIndex = true - cf.AllowRemoteLookup = true - cf.AvoidCircularReferenceCheck = true - cf.BasePath = "../test_specs" - cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ - Level: slog.LevelError, - })) + // create a new config that allows local and remote to be mixed up. + cf := CreateOpenAPIIndexConfig() + cf.AvoidBuildIndex = true + cf.AllowRemoteLookup = true + cf.AvoidCircularReferenceCheck = true + cf.BasePath = "../test_specs" + cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelError, + })) - // setting this baseURL will override the base - cf.BaseURL, _ = url.Parse(server.URL) + // setting this baseURL will override the base + cf.BaseURL, _ = url.Parse(server.URL) - cFile := "../test_specs/mixedref-burgershop.openapi.yaml" - yml, _ := os.ReadFile(cFile) - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + cFile := "../test_specs/mixedref-burgershop.openapi.yaml" + yml, _ := os.ReadFile(cFile) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - // create a new rolodex - rolo := NewRolodex(cf) + // create a new rolodex + rolo := NewRolodex(cf) - // set the rolodex root node to the root node of the spec. - rolo.SetRootNode(&rootNode) + // set the rolodex root node to the root node of the spec. + rolo.SetRootNode(&rootNode) - // create a new remote fs and set the config for indexing. - remoteFS, _ := NewRemoteFSWithRootURL(server.URL) - remoteFS.SetIndexConfig(cf) + // create a new remote fs and set the config for indexing. + remoteFS, _ := NewRemoteFSWithRootURL(server.URL) + remoteFS.SetIndexConfig(cf) - // set our remote handler func + // set our remote handler func - c := http.Client{} + c := http.Client{} - remoteFS.RemoteHandlerFunc = c.Get + remoteFS.RemoteHandlerFunc = c.Get - // configure the local filesystem. - fsCfg := LocalFSConfig{ - BaseDirectory: cf.BasePath, - FileFilters: []string{"burgershop.openapi.yaml"}, - DirFS: os.DirFS(cf.BasePath), - } + // configure the local filesystem. + fsCfg := LocalFSConfig{ + BaseDirectory: cf.BasePath, + FileFilters: []string{"burgershop.openapi.yaml"}, + DirFS: os.DirFS(cf.BasePath), + } - // create a new local filesystem. - fileFS, err := NewLocalFSWithConfig(&fsCfg) - assert.NoError(t, err) + // create a new local filesystem. + fileFS, err := NewLocalFSWithConfig(&fsCfg) + assert.NoError(t, err) - // add file systems to the rolodex - rolo.AddLocalFS(cf.BasePath, fileFS) - rolo.AddRemoteFS(server.URL, remoteFS) + // add file systems to the rolodex + rolo.AddLocalFS(cf.BasePath, fileFS) + rolo.AddRemoteFS(server.URL, remoteFS) - // index the rolodex. - indexedErr := rolo.IndexTheRolodex() - rolo.BuildIndexes() + // index the rolodex. + indexedErr := rolo.IndexTheRolodex() + rolo.BuildIndexes() - assert.NoError(t, indexedErr) + assert.NoError(t, indexedErr) - index := rolo.GetRootIndex() - rolo.CheckForCircularReferences() + index := rolo.GetRootIndex() + rolo.CheckForCircularReferences() - assert.Len(t, index.allRefs, 5) - assert.Len(t, index.allMappedRefs, 5) - assert.Equal(t, 5, index.GetPathCount()) - assert.Equal(t, 5, index.GetOperationCount()) - assert.Equal(t, 1, index.GetComponentSchemaCount()) - assert.Equal(t, 2, index.GetGlobalTagsCount()) - assert.Equal(t, 3, index.GetTotalTagsCount()) - assert.Equal(t, 2, index.GetOperationTagsCount()) - assert.Equal(t, 0, index.GetGlobalLinksCount()) - assert.Equal(t, 0, index.GetComponentParameterCount()) - assert.Equal(t, 2, index.GetOperationsParameterCount()) - assert.Equal(t, 1, index.GetInlineDuplicateParamCount()) - assert.Equal(t, 1, index.GetInlineUniqueParamCount()) - assert.Len(t, index.refErrors, 0) - assert.Len(t, index.GetCircularReferences(), 0) + assert.Len(t, index.allRefs, 5) + assert.Len(t, index.allMappedRefs, 5) + assert.Equal(t, 5, index.GetPathCount()) + assert.Equal(t, 5, index.GetOperationCount()) + assert.Equal(t, 1, index.GetComponentSchemaCount()) + assert.Equal(t, 2, index.GetGlobalTagsCount()) + assert.Equal(t, 3, index.GetTotalTagsCount()) + assert.Equal(t, 2, index.GetOperationTagsCount()) + assert.Equal(t, 0, index.GetGlobalLinksCount()) + assert.Equal(t, 0, index.GetComponentParameterCount()) + assert.Equal(t, 2, index.GetOperationsParameterCount()) + assert.Equal(t, 1, index.GetInlineDuplicateParamCount()) + assert.Equal(t, 1, index.GetInlineUniqueParamCount()) + assert.Len(t, index.refErrors, 0) + assert.Len(t, index.GetCircularReferences(), 0) - // get the size of the rolodex. - assert.Equal(t, int64(60232), rolo.RolodexFileSize()+int64(len(yml))) - assert.Equal(t, "50.48 KB", rolo.RolodexFileSizeAsString()) - assert.Equal(t, 3, rolo.RolodexTotalFiles()) + // get the size of the rolodex. + assert.Equal(t, int64(60232), rolo.RolodexFileSize()+int64(len(yml))) + assert.Equal(t, "50.48 KB", rolo.RolodexFileSizeAsString()) + assert.Equal(t, 3, rolo.RolodexTotalFiles()) } func TestCalcSizeAsString(t *testing.T) { - assert.Equal(t, "345 B", HumanFileSize(345)) - assert.Equal(t, "1 KB", HumanFileSize(1024)) - assert.Equal(t, "1 KB", HumanFileSize(1025)) - assert.Equal(t, "1.98 KB", HumanFileSize(2025)) - assert.Equal(t, "1 MB", HumanFileSize(1025*1024)) - assert.Equal(t, "1 GB", HumanFileSize(1025*1025*1025)) + assert.Equal(t, "345 B", HumanFileSize(345)) + assert.Equal(t, "1 KB", HumanFileSize(1024)) + assert.Equal(t, "1 KB", HumanFileSize(1025)) + assert.Equal(t, "1.98 KB", HumanFileSize(2025)) + assert.Equal(t, "1 MB", HumanFileSize(1025*1024)) + assert.Equal(t, "1 GB", HumanFileSize(1025*1025*1025)) } func TestSpecIndex_TestEmptyBrokenReferences(t *testing.T) { - badref, _ := os.ReadFile("../test_specs/badref-burgershop.openapi.yaml") - var rootNode yaml.Node - _ = yaml.Unmarshal(badref, &rootNode) + badref, _ := os.ReadFile("../test_specs/badref-burgershop.openapi.yaml") + var rootNode yaml.Node + _ = yaml.Unmarshal(badref, &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Equal(t, 5, index.GetPathCount()) - assert.Equal(t, 5, index.GetOperationCount()) - assert.Equal(t, 5, index.GetComponentSchemaCount()) - assert.Equal(t, 2, index.GetGlobalTagsCount()) - assert.Equal(t, 3, index.GetTotalTagsCount()) - assert.Equal(t, 2, index.GetOperationTagsCount()) - assert.Equal(t, 2, index.GetGlobalLinksCount()) - assert.Equal(t, 0, index.GetComponentParameterCount()) - assert.Equal(t, 2, index.GetOperationsParameterCount()) - assert.Equal(t, 1, index.GetInlineDuplicateParamCount()) - assert.Equal(t, 1, index.GetInlineUniqueParamCount()) - assert.Len(t, index.refErrors, 6) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + assert.Equal(t, 5, index.GetPathCount()) + assert.Equal(t, 5, index.GetOperationCount()) + assert.Equal(t, 5, index.GetComponentSchemaCount()) + assert.Equal(t, 2, index.GetGlobalTagsCount()) + assert.Equal(t, 3, index.GetTotalTagsCount()) + assert.Equal(t, 2, index.GetOperationTagsCount()) + assert.Equal(t, 2, index.GetGlobalLinksCount()) + assert.Equal(t, 0, index.GetComponentParameterCount()) + assert.Equal(t, 2, index.GetOperationsParameterCount()) + assert.Equal(t, 1, index.GetInlineDuplicateParamCount()) + assert.Equal(t, 1, index.GetInlineUniqueParamCount()) + assert.Len(t, index.refErrors, 6) } func TestTagsNoDescription(t *testing.T) { - yml := `tags: + yml := `tags: - name: one - name: two - three: three` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Equal(t, 3, index.GetGlobalTagsCount()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + assert.Equal(t, 3, index.GetGlobalTagsCount()) } func TestGlobalCallbacksNoIndexTest(t *testing.T) { - idx := new(SpecIndex) - assert.Equal(t, -1, idx.GetGlobalCallbacksCount()) + idx := new(SpecIndex) + assert.Equal(t, -1, idx.GetGlobalCallbacksCount()) } func TestMultipleCallbacksPerOperationVerb(t *testing.T) { - yml := `components: + yml := `components: callbacks: callbackA: "{$request.query.queryUrl}": @@ -876,15 +876,15 @@ paths: callbackA: $ref: '#/components/callbacks/CallbackA'` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Equal(t, 4, index.GetGlobalCallbacksCount()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + assert.Equal(t, 4, index.GetGlobalCallbacksCount()) } func TestSpecIndex_ExtractComponentsFromRefs(t *testing.T) { - yml := `components: + yml := `components: schemas: pizza: properties: @@ -893,15 +893,15 @@ func TestSpecIndex_ExtractComponentsFromRefs(t *testing.T) { something: description: something` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Len(t, index.GetReferenceIndexErrors(), 1) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + assert.Len(t, index.GetReferenceIndexErrors(), 1) } func TestSpecIndex_FindComponent_WithACrazyAssPath(t *testing.T) { - yml := `paths: + yml := `paths: /crazy/ass/references: get: parameters: @@ -935,19 +935,19 @@ func TestSpecIndex_FindComponent_WithACrazyAssPath(t *testing.T) { $ref: "#/paths/~1crazy~1ass~1references/get/responses/404/content/application~1xml;%20charset=utf-8/schema" description: Not Found.` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Equal(t, "#/paths/~1crazy~1ass~1references/get/parameters/0", - index.FindComponent("#/paths/~1crazy~1ass~1references/get/responses/404/content/application~1xml;%20charset=utf-8/schema").Node.Content[1].Value) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + assert.Equal(t, "#/paths/~1crazy~1ass~1references/get/parameters/0", + index.FindComponent("#/paths/~1crazy~1ass~1references/get/responses/404/content/application~1xml;%20charset=utf-8/schema").Node.Content[1].Value) - assert.Equal(t, "a param", - index.FindComponent("#/paths/~1crazy~1ass~1references/get/parameters/0").Node.Content[1].Value) + assert.Equal(t, "a param", + index.FindComponent("#/paths/~1crazy~1ass~1references/get/parameters/0").Node.Content[1].Value) } func TestSpecIndex_FindComponent(t *testing.T) { - yml := `components: + yml := `components: schemas: pizza: properties: @@ -956,15 +956,15 @@ func TestSpecIndex_FindComponent(t *testing.T) { something: description: something` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Nil(t, index.FindComponent("I-do-not-exist")) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + assert.Nil(t, index.FindComponent("I-do-not-exist")) } func TestSpecIndex_TestPathsNodeAsArray(t *testing.T) { - yml := `components: + yml := `components: schemas: pizza: properties: @@ -973,193 +973,193 @@ func TestSpecIndex_TestPathsNodeAsArray(t *testing.T) { something: description: something` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Nil(t, index.lookupRolodex(nil)) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + assert.Nil(t, index.lookupRolodex(nil)) } func TestSpecIndex_CheckBadURLRefNoRemoteAllowed(t *testing.T) { - yml := `openapi: 3.1.0 + yml := `openapi: 3.1.0 paths: /cakes: post: parameters: - $ref: 'httpsss://badurl'` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - c := CreateClosedAPIIndexConfig() - idx := NewSpecIndexWithConfig(&rootNode, c) + c := CreateClosedAPIIndexConfig() + idx := NewSpecIndexWithConfig(&rootNode, c) - assert.Len(t, idx.refErrors, 1) + assert.Len(t, idx.refErrors, 1) } func TestSpecIndex_CheckIndexDiscoversNoComponentLocalFileReference(t *testing.T) { - c := []byte("name: time for coffee") + c := []byte("name: time for coffee") - _ = os.WriteFile("coffee-time.yaml", c, 0o664) - defer os.Remove("coffee-time.yaml") + _ = os.WriteFile("coffee-time.yaml", c, 0o664) + defer os.Remove("coffee-time.yaml") - // create a new config that allows local and remote to be mixed up. - cf := CreateOpenAPIIndexConfig() - cf.AvoidCircularReferenceCheck = true - cf.BasePath = "." + // create a new config that allows local and remote to be mixed up. + cf := CreateOpenAPIIndexConfig() + cf.AvoidCircularReferenceCheck = true + cf.BasePath = "." - // create a new rolodex - rolo := NewRolodex(cf) + // create a new rolodex + rolo := NewRolodex(cf) - // configure the local filesystem. - fsCfg := LocalFSConfig{ - BaseDirectory: cf.BasePath, - FileFilters: []string{"coffee-time.yaml"}, - DirFS: os.DirFS(cf.BasePath), - } + // configure the local filesystem. + fsCfg := LocalFSConfig{ + BaseDirectory: cf.BasePath, + FileFilters: []string{"coffee-time.yaml"}, + DirFS: os.DirFS(cf.BasePath), + } - // create a new local filesystem. - fileFS, err := NewLocalFSWithConfig(&fsCfg) - assert.NoError(t, err) + // create a new local filesystem. + fileFS, err := NewLocalFSWithConfig(&fsCfg) + assert.NoError(t, err) - yml := `openapi: 3.0.3 + yml := `openapi: 3.0.3 paths: /cakes: post: parameters: - $ref: 'coffee-time.yaml'` - var coffee yaml.Node - _ = yaml.Unmarshal([]byte(yml), &coffee) + var coffee yaml.Node + _ = yaml.Unmarshal([]byte(yml), &coffee) - // set the rolodex root node to the root node of the spec. - rolo.SetRootNode(&coffee) + // set the rolodex root node to the root node of the spec. + rolo.SetRootNode(&coffee) - rolo.AddLocalFS(cf.BasePath, fileFS) - rErr := rolo.IndexTheRolodex() + rolo.AddLocalFS(cf.BasePath, fileFS) + rErr := rolo.IndexTheRolodex() - assert.NoError(t, rErr) + assert.NoError(t, rErr) - index := rolo.GetRootIndex() + index := rolo.GetRootIndex() - assert.NotNil(t, index.GetAllParametersFromOperations()["/cakes"]["post"]["coffee-time.yaml"][0].Node) + assert.NotNil(t, index.GetAllParametersFromOperations()["/cakes"]["post"]["coffee-time.yaml"][0].Node) } func TestSpecIndex_lookupFileReference_MultiRes(t *testing.T) { - embie := []byte("naughty:\n - puppy: dog\n - puppy: naughty\npuppy:\n - naughty: puppy") + embie := []byte("naughty:\n - puppy: dog\n - puppy: naughty\npuppy:\n - naughty: puppy") - _ = os.WriteFile("embie.yaml", embie, 0o664) - defer os.Remove("embie.yaml") + _ = os.WriteFile("embie.yaml", embie, 0o664) + defer os.Remove("embie.yaml") - // create a new config that allows local and remote to be mixed up. - cf := CreateOpenAPIIndexConfig() - cf.AvoidBuildIndex = true - cf.AvoidCircularReferenceCheck = true - cf.BasePath = "." + // create a new config that allows local and remote to be mixed up. + cf := CreateOpenAPIIndexConfig() + cf.AvoidBuildIndex = true + cf.AvoidCircularReferenceCheck = true + cf.BasePath = "." - // create a new rolodex - rolo := NewRolodex(cf) + // create a new rolodex + rolo := NewRolodex(cf) - var myPuppy yaml.Node - _ = yaml.Unmarshal(embie, &myPuppy) + var myPuppy yaml.Node + _ = yaml.Unmarshal(embie, &myPuppy) - // set the rolodex root node to the root node of the spec. - rolo.SetRootNode(&myPuppy) + // set the rolodex root node to the root node of the spec. + rolo.SetRootNode(&myPuppy) - // configure the local filesystem. - fsCfg := LocalFSConfig{ - BaseDirectory: cf.BasePath, - FileFilters: []string{"embie.yaml"}, - DirFS: os.DirFS(cf.BasePath), - } + // configure the local filesystem. + fsCfg := LocalFSConfig{ + BaseDirectory: cf.BasePath, + FileFilters: []string{"embie.yaml"}, + DirFS: os.DirFS(cf.BasePath), + } - // create a new local filesystem. - fileFS, err := NewLocalFSWithConfig(&fsCfg) - assert.NoError(t, err) + // create a new local filesystem. + fileFS, err := NewLocalFSWithConfig(&fsCfg) + assert.NoError(t, err) - rolo.AddLocalFS(cf.BasePath, fileFS) - rErr := rolo.IndexTheRolodex() + rolo.AddLocalFS(cf.BasePath, fileFS) + rErr := rolo.IndexTheRolodex() - assert.NoError(t, rErr) + assert.NoError(t, rErr) - embieRoloFile, fErr := rolo.Open("embie.yaml") + embieRoloFile, fErr := rolo.Open("embie.yaml") - assert.NoError(t, fErr) - assert.NotNil(t, embieRoloFile) + assert.NoError(t, fErr) + assert.NotNil(t, embieRoloFile) - index := rolo.GetRootIndex() - //index.seenRemoteSources = make(map[string]*yaml.Node) - absoluteRef, _ := filepath.Abs("embie.yaml#/naughty") - fRef, _ := index.SearchIndexForReference(absoluteRef) - assert.NotNil(t, fRef) + index := rolo.GetRootIndex() + //index.seenRemoteSources = make(map[string]*yaml.Node) + absoluteRef, _ := filepath.Abs("embie.yaml#/naughty") + fRef, _ := index.SearchIndexForReference(absoluteRef) + assert.NotNil(t, fRef) } func TestSpecIndex_lookupFileReference(t *testing.T) { - pup := []byte("good:\n - puppy: dog\n - puppy: forever-more") + pup := []byte("good:\n - puppy: dog\n - puppy: forever-more") - var myPuppy yaml.Node - _ = yaml.Unmarshal(pup, &myPuppy) + var myPuppy yaml.Node + _ = yaml.Unmarshal(pup, &myPuppy) - _ = os.WriteFile("fox.yaml", pup, 0o664) - defer os.Remove("fox.yaml") + _ = os.WriteFile("fox.yaml", pup, 0o664) + defer os.Remove("fox.yaml") - // create a new config that allows local and remote to be mixed up. - cf := CreateOpenAPIIndexConfig() - cf.AvoidBuildIndex = true - cf.AvoidCircularReferenceCheck = true - cf.BasePath = "." + // create a new config that allows local and remote to be mixed up. + cf := CreateOpenAPIIndexConfig() + cf.AvoidBuildIndex = true + cf.AvoidCircularReferenceCheck = true + cf.BasePath = "." - // create a new rolodex - rolo := NewRolodex(cf) + // create a new rolodex + rolo := NewRolodex(cf) - // set the rolodex root node to the root node of the spec. - rolo.SetRootNode(&myPuppy) + // set the rolodex root node to the root node of the spec. + rolo.SetRootNode(&myPuppy) - // configure the local filesystem. - fsCfg := LocalFSConfig{ - BaseDirectory: cf.BasePath, - FileFilters: []string{"fox.yaml"}, - DirFS: os.DirFS(cf.BasePath), - } + // configure the local filesystem. + fsCfg := LocalFSConfig{ + BaseDirectory: cf.BasePath, + FileFilters: []string{"fox.yaml"}, + DirFS: os.DirFS(cf.BasePath), + } - // create a new local filesystem. - fileFS, err := NewLocalFSWithConfig(&fsCfg) - assert.NoError(t, err) + // create a new local filesystem. + fileFS, err := NewLocalFSWithConfig(&fsCfg) + assert.NoError(t, err) - rolo.AddLocalFS(cf.BasePath, fileFS) - rErr := rolo.IndexTheRolodex() + rolo.AddLocalFS(cf.BasePath, fileFS) + rErr := rolo.IndexTheRolodex() - assert.NoError(t, rErr) + assert.NoError(t, rErr) - fox, fErr := rolo.Open("fox.yaml") - assert.NoError(t, fErr) - assert.Equal(t, "fox.yaml", fox.Name()) - assert.Equal(t, "good:\n - puppy: dog\n - puppy: forever-more", string(fox.GetContent())) + fox, fErr := rolo.Open("fox.yaml") + assert.NoError(t, fErr) + assert.Equal(t, "fox.yaml", fox.Name()) + assert.Equal(t, "good:\n - puppy: dog\n - puppy: forever-more", string(fox.GetContent())) } func TestSpecIndex_parameterReferencesHavePaths(t *testing.T) { - _ = os.WriteFile("paramour.yaml", []byte(`components: + _ = os.WriteFile("paramour.yaml", []byte(`components: parameters: param3: name: param3 in: query schema: type: string`), 0o664) - defer os.Remove("paramour.yaml") + defer os.Remove("paramour.yaml") - // create a new config that allows local and remote to be mixed up. - cf := CreateOpenAPIIndexConfig() - cf.AvoidBuildIndex = true - cf.AllowRemoteLookup = true - cf.AvoidCircularReferenceCheck = true - cf.BasePath = "." + // create a new config that allows local and remote to be mixed up. + cf := CreateOpenAPIIndexConfig() + cf.AvoidBuildIndex = true + cf.AllowRemoteLookup = true + cf.AvoidCircularReferenceCheck = true + cf.BasePath = "." - yml := `paths: + yml := `paths: /: parameters: - $ref: '#/components/parameters/param1' @@ -1186,60 +1186,60 @@ components: schema: type: string` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - // create a new rolodex - rolo := NewRolodex(cf) + // create a new rolodex + rolo := NewRolodex(cf) - // set the rolodex root node to the root node of the spec. - rolo.SetRootNode(&rootNode) + // set the rolodex root node to the root node of the spec. + rolo.SetRootNode(&rootNode) - // configure the local filesystem. - fsCfg := LocalFSConfig{ - BaseDirectory: cf.BasePath, - FileFilters: []string{"paramour.yaml"}, - DirFS: os.DirFS(cf.BasePath), - } + // configure the local filesystem. + fsCfg := LocalFSConfig{ + BaseDirectory: cf.BasePath, + FileFilters: []string{"paramour.yaml"}, + DirFS: os.DirFS(cf.BasePath), + } - // create a new local filesystem. - fileFS, err := NewLocalFSWithConfig(&fsCfg) - assert.NoError(t, err) + // create a new local filesystem. + fileFS, err := NewLocalFSWithConfig(&fsCfg) + assert.NoError(t, err) - // add file system - rolo.AddLocalFS(cf.BasePath, fileFS) + // add file system + rolo.AddLocalFS(cf.BasePath, fileFS) - // index the rolodex. - indexedErr := rolo.IndexTheRolodex() - assert.NoError(t, indexedErr) - rolo.BuildIndexes() + // index the rolodex. + indexedErr := rolo.IndexTheRolodex() + assert.NoError(t, indexedErr) + rolo.BuildIndexes() - index := rolo.GetRootIndex() + index := rolo.GetRootIndex() - params := index.GetAllParametersFromOperations() + params := index.GetAllParametersFromOperations() - if assert.Contains(t, params, "/") { - if assert.Contains(t, params["/"], "top") { - if assert.Contains(t, params["/"]["top"], "#/components/parameters/param1") { - assert.Equal(t, "$.components.parameters.param1", params["/"]["top"]["#/components/parameters/param1"][0].Path) - } - if assert.Contains(t, params["/"]["top"], "paramour.yaml#/components/parameters/param3") { - assert.Equal(t, "$.components.parameters.param3", params["/"]["top"]["paramour.yaml#/components/parameters/param3"][0].Path) - } - } - if assert.Contains(t, params["/"], "get") { - if assert.Contains(t, params["/"]["get"], "#/components/parameters/param2") { - assert.Equal(t, "$.components.parameters.param2", params["/"]["get"]["#/components/parameters/param2"][0].Path) - } - if assert.Contains(t, params["/"]["get"], "test") { - assert.Equal(t, "$.paths./.get.parameters[2]", params["/"]["get"]["test"][0].Path) - } - } - } + if assert.Contains(t, params, "/") { + if assert.Contains(t, params["/"], "top") { + if assert.Contains(t, params["/"]["top"], "#/components/parameters/param1") { + assert.Equal(t, "$.components.parameters.param1", params["/"]["top"]["#/components/parameters/param1"][0].Path) + } + if assert.Contains(t, params["/"]["top"], "paramour.yaml#/components/parameters/param3") { + assert.Equal(t, "$.components.parameters.param3", params["/"]["top"]["paramour.yaml#/components/parameters/param3"][0].Path) + } + } + if assert.Contains(t, params["/"], "get") { + if assert.Contains(t, params["/"]["get"], "#/components/parameters/param2") { + assert.Equal(t, "$.components.parameters.param2", params["/"]["get"]["#/components/parameters/param2"][0].Path) + } + if assert.Contains(t, params["/"]["get"], "test") { + assert.Equal(t, "$.paths./.get.parameters[2]", params["/"]["get"]["test"][0].Path) + } + } + } } func TestSpecIndex_serverReferencesHaveParentNodesAndPaths(t *testing.T) { - yml := `servers: + yml := `servers: - url: https://api.example.com/v1 paths: /: @@ -1249,59 +1249,59 @@ paths: servers: - url: https://api.example.com/v3` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - rootServers := index.GetAllRootServers() + rootServers := index.GetAllRootServers() - for i, server := range rootServers { - assert.NotNil(t, server.ParentNode) - assert.Equal(t, fmt.Sprintf("$.servers[%d]", i), server.Path) - } + for i, server := range rootServers { + assert.NotNil(t, server.ParentNode) + assert.Equal(t, fmt.Sprintf("$.servers[%d]", i), server.Path) + } - opServers := index.GetAllOperationsServers() + opServers := index.GetAllOperationsServers() - for path, ops := range opServers { - for op, servers := range ops { - for i, server := range servers { - assert.NotNil(t, server.ParentNode) + for path, ops := range opServers { + for op, servers := range ops { + for i, server := range servers { + assert.NotNil(t, server.ParentNode) - opPath := fmt.Sprintf(".%s", op) - if op == "top" { - opPath = "" - } + opPath := fmt.Sprintf(".%s", op) + if op == "top" { + opPath = "" + } - assert.Equal(t, fmt.Sprintf("$.paths.%s%s.servers[%d]", path, opPath, i), server.Path) - } - } - } + assert.Equal(t, fmt.Sprintf("$.paths.%s%s.servers[%d]", path, opPath, i), server.Path) + } + } + } } func TestSpecIndex_schemaComponentsHaveParentsAndPaths(t *testing.T) { - yml := `components: + yml := `components: schemas: Pet: type: object Dog: type: object` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - schemas := index.GetAllSchemas() + schemas := index.GetAllSchemas() - for _, schema := range schemas { - assert.NotNil(t, schema.ParentNode) - assert.Equal(t, fmt.Sprintf("$.components.schemas.%s", schema.Name), schema.Path) - } + for _, schema := range schemas { + assert.NotNil(t, schema.ParentNode) + assert.Equal(t, fmt.Sprintf("$.components.schemas.%s", schema.Name), schema.Path) + } } func TestSpecIndex_ParamsWithDuplicateNamesButUniqueInTypes(t *testing.T) { - yml := `openapi: 3.1.0 + yml := `openapi: 3.1.0 info: title: Test version: 0.0.1 @@ -1337,19 +1337,19 @@ paths: "200": description: OK` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Len(t, idx.paramAllRefs, 4) - assert.Len(t, idx.paramInlineDuplicateNames, 2) - assert.Len(t, idx.operationParamErrors, 0) - assert.Len(t, idx.refErrors, 0) + assert.Len(t, idx.paramAllRefs, 4) + assert.Len(t, idx.paramInlineDuplicateNames, 2) + assert.Len(t, idx.operationParamErrors, 0) + assert.Len(t, idx.refErrors, 0) } func TestSpecIndex_ParamsWithDuplicateNamesAndSameInTypes(t *testing.T) { - yml := `openapi: 3.1.0 + yml := `openapi: 3.1.0 info: title: Test version: 0.0.1 @@ -1385,19 +1385,19 @@ paths: "200": description: OK` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Len(t, idx.paramAllRefs, 3) - assert.Len(t, idx.paramInlineDuplicateNames, 2) - assert.Len(t, idx.operationParamErrors, 1) - assert.Len(t, idx.refErrors, 0) + assert.Len(t, idx.paramAllRefs, 3) + assert.Len(t, idx.paramInlineDuplicateNames, 2) + assert.Len(t, idx.operationParamErrors, 1) + assert.Len(t, idx.refErrors, 0) } func TestSpecIndex_foundObjectsWithProperties(t *testing.T) { - yml := `paths: + yml := `paths: /test: get: responses: @@ -1425,64 +1425,64 @@ components: type: object additionalProperties: true` - var rootNode yaml.Node - yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + yaml.Unmarshal([]byte(yml), &rootNode) - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - objects := index.GetAllObjectsWithProperties() - assert.Len(t, objects, 3) + objects := index.GetAllObjectsWithProperties() + assert.Len(t, objects, 3) } // Example of how to load in an OpenAPI Specification and index it. func ExampleNewSpecIndex() { - // define a rootNode to hold our raw spec AST. - var rootNode yaml.Node + // define a rootNode to hold our raw spec AST. + var rootNode yaml.Node - // load in the stripe OpenAPI specification into bytes (it's pretty meaty) - stripeSpec, _ := os.ReadFile("../test_specs/stripe.yaml") + // load in the stripe OpenAPI specification into bytes (it's pretty meaty) + stripeSpec, _ := os.ReadFile("../test_specs/stripe.yaml") - // unmarshal spec into our rootNode - _ = yaml.Unmarshal(stripeSpec, &rootNode) + // unmarshal spec into our rootNode + _ = yaml.Unmarshal(stripeSpec, &rootNode) - // create a new specification index. - index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + // create a new specification index. + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - // print out some statistics - fmt.Printf("There are %d references\n"+ - "%d paths\n"+ - "%d operations\n"+ - "%d component schemas\n"+ - "%d reference schemas\n"+ - "%d inline schemas\n"+ - "%d inline schemas that are objects or arrays\n"+ - "%d total schemas\n"+ - "%d enums\n"+ - "%d polymorphic references", - len(index.GetAllCombinedReferences()), - len(index.GetAllPaths()), - index.GetOperationCount(), - len(index.GetAllComponentSchemas()), - len(index.GetAllReferenceSchemas()), - len(index.GetAllInlineSchemas()), - len(index.GetAllInlineSchemaObjects()), - len(index.GetAllSchemas()), - len(index.GetAllEnums()), - len(index.GetPolyOneOfReferences())+len(index.GetPolyAnyOfReferences())) - // Output: There are 871 references - // 336 paths - // 494 operations - // 871 component schemas - // 2712 reference schemas - // 15928 inline schemas - // 3857 inline schemas that are objects or arrays - // 19511 total schemas - // 2579 enums - // 1023 polymorphic references + // print out some statistics + fmt.Printf("There are %d references\n"+ + "%d paths\n"+ + "%d operations\n"+ + "%d component schemas\n"+ + "%d reference schemas\n"+ + "%d inline schemas\n"+ + "%d inline schemas that are objects or arrays\n"+ + "%d total schemas\n"+ + "%d enums\n"+ + "%d polymorphic references", + len(index.GetAllCombinedReferences()), + len(index.GetAllPaths()), + index.GetOperationCount(), + len(index.GetAllComponentSchemas()), + len(index.GetAllReferenceSchemas()), + len(index.GetAllInlineSchemas()), + len(index.GetAllInlineSchemaObjects()), + len(index.GetAllSchemas()), + len(index.GetAllEnums()), + len(index.GetPolyOneOfReferences())+len(index.GetPolyAnyOfReferences())) + // Output: There are 871 references + // 336 paths + // 494 operations + // 871 component schemas + // 2712 reference schemas + // 15928 inline schemas + // 3857 inline schemas that are objects or arrays + // 19511 total schemas + // 2579 enums + // 1023 polymorphic references } func TestSpecIndex_GetAllPathsHavePathAndParent(t *testing.T) { - yml := `openapi: 3.1.0 + yml := `openapi: 3.1.0 info: title: Test version: 0.0.1 @@ -1508,19 +1508,19 @@ paths: "200": description: OK` - var rootNode yaml.Node - _ = yaml.Unmarshal([]byte(yml), &rootNode) + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(yml), &rootNode) - idx := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + idx := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - paths := idx.GetAllPaths() + paths := idx.GetAllPaths() - assert.Equal(t, "$.paths./test.get", paths["/test"]["get"].Path) - assert.Equal(t, 9, paths["/test"]["get"].ParentNode.Line) - assert.Equal(t, "$.paths./test.post", paths["/test"]["post"].Path) - assert.Equal(t, 13, paths["/test"]["post"].ParentNode.Line) - assert.Equal(t, "$.paths./test2.delete", paths["/test2"]["delete"].Path) - assert.Equal(t, 18, paths["/test2"]["delete"].ParentNode.Line) - assert.Equal(t, "$.paths./test2.put", paths["/test2"]["put"].Path) - assert.Equal(t, 22, paths["/test2"]["put"].ParentNode.Line) + assert.Equal(t, "$.paths./test.get", paths["/test"]["get"].Path) + assert.Equal(t, 9, paths["/test"]["get"].ParentNode.Line) + assert.Equal(t, "$.paths./test.post", paths["/test"]["post"].Path) + assert.Equal(t, 13, paths["/test"]["post"].ParentNode.Line) + assert.Equal(t, "$.paths./test2.delete", paths["/test2"]["delete"].Path) + assert.Equal(t, 18, paths["/test2"]["delete"].ParentNode.Line) + assert.Equal(t, "$.paths./test2.put", paths["/test2"]["put"].Path) + assert.Equal(t, 22, paths["/test2"]["put"].ParentNode.Line) }