Merge branch 'main' into ordered-libopenapi

This commit is contained in:
Tristan Cartledge
2023-12-01 17:57:05 +00:00
14 changed files with 174704 additions and 54215 deletions

View File

@@ -435,7 +435,7 @@ func TestStripeAsDoc(t *testing.T) {
info, _ := datamodel.ExtractSpecInfo(data) info, _ := datamodel.ExtractSpecInfo(data)
var err error var err error
lowDoc, err = lowv3.CreateDocumentFromConfig(info, datamodel.NewDocumentConfiguration()) lowDoc, err = lowv3.CreateDocumentFromConfig(info, datamodel.NewDocumentConfiguration())
assert.Len(t, utils.UnwrapErrors(err), 3) assert.Len(t, utils.UnwrapErrors(err), 2)
d := NewDocument(lowDoc) d := NewDocument(lowDoc)
assert.NotNil(t, d) assert.NotNil(t, d)
} }

View File

@@ -262,7 +262,7 @@ func TestCreateDocumentStripe(t *testing.T) {
data, _ := os.ReadFile("../../../test_specs/stripe.yaml") data, _ := os.ReadFile("../../../test_specs/stripe.yaml")
info, _ := datamodel.ExtractSpecInfo(data) info, _ := datamodel.ExtractSpecInfo(data)
d, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{}) d, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{})
assert.Len(t, utils.UnwrapErrors(err), 3) assert.Len(t, utils.UnwrapErrors(err), 2)
assert.Equal(t, "3.0.0", d.Version.Value) assert.Equal(t, "3.0.0", d.Version.Value)
assert.Equal(t, "Stripe API", d.Info.Value.Title.Value) assert.Equal(t, "Stripe API", d.Info.Value.Title.Value)

View File

@@ -262,6 +262,7 @@ func TestDocument_RenderAndReload_ChangeCheck_Burgershop(t *testing.T) {
// should noth be nil. // should noth be nil.
assert.Nil(t, errs) assert.Nil(t, errs)
assert.Nil(t, errs)
assert.NotNil(t, rend) assert.NotNil(t, rend)
assert.Nil(t, compReport) assert.Nil(t, compReport)
} }
@@ -291,12 +292,28 @@ func TestDocument_RenderAndReload_ChangeCheck_Stripe(t *testing.T) {
tc := compReport.TotalChanges() tc := compReport.TotalChanges()
bc := compReport.TotalBreakingChanges() bc := compReport.TotalBreakingChanges()
assert.Equal(t, 0, bc) assert.Equal(t, 0, bc)
assert.Equal(t, 519, tc) assert.Equal(t, 819, tc)
// there should be no other changes than the 519 descriptions. // there should be no other changes than the 519 descriptions.
assert.Equal(t, 0, len(filtered)) assert.Equal(t, 0, len(filtered))
} }
func TestDocument_ResolveStripe(t *testing.T) {
bs, _ := os.ReadFile("test_specs/stripe.yaml")
docConfig := datamodel.NewDocumentConfiguration()
docConfig.SkipCircularReferenceCheck = true
docConfig.BasePath = "."
docConfig.AllowRemoteReferences = true
docConfig.AllowFileReferences = true
doc, _ := NewDocumentWithConfiguration(bs, docConfig)
model, _ := doc.BuildV3Model()
rolo := model.Index.GetRolodex()
rolo.Resolve()
assert.Equal(t, 2, len(model.Index.GetRolodex().GetCaughtErrors()))
}
func TestDocument_RenderAndReload_ChangeCheck_Asana(t *testing.T) { func TestDocument_RenderAndReload_ChangeCheck_Asana(t *testing.T) {
bs, _ := os.ReadFile("test_specs/asana.yaml") bs, _ := os.ReadFile("test_specs/asana.yaml")
doc, _ := NewDocument(bs) doc, _ := NewDocument(bs)

View File

@@ -332,7 +332,8 @@ func (resolver *Resolver) VisitReference(ref *Reference, seen map[string]bool, j
loop := append(journey, foundDup) loop := append(journey, foundDup)
visitedDefinitions := make(map[string]bool) visitedDefinitions := make(map[string]bool)
isInfiniteLoop, _ := resolver.isInfiniteCircularDependency(foundDup, visitedDefinitions, nil) isInfiniteLoop, _ := resolver.isInfiniteCircularDependency(foundDup,
visitedDefinitions, nil)
isArray := false isArray := false
if r.ParentNodeSchemaType == "array" || slices.Contains(r.ParentNodeTypes, "array") { if r.ParentNodeSchemaType == "array" || slices.Contains(r.ParentNodeTypes, "array") {
@@ -382,11 +383,11 @@ func (resolver *Resolver) VisitReference(ref *Reference, seen map[string]bool, j
return ref.Node.Content return ref.Node.Content
} }
func (resolver *Resolver) isInfiniteCircularDependency(ref *Reference, visitedDefinitions map[string]bool, initialRef *Reference) (bool, map[string]bool) { func (resolver *Resolver) isInfiniteCircularDependency(ref *Reference, visitedDefinitions map[string]bool,
initialRef *Reference) (bool, map[string]bool) {
if ref == nil { if ref == nil {
return false, visitedDefinitions return false, visitedDefinitions
} }
for refDefinition := range ref.RequiredRefProperties { for refDefinition := range ref.RequiredRefProperties {
r, _ := resolver.specIndex.SearchIndexForReference(refDefinition) r, _ := resolver.specIndex.SearchIndexForReference(refDefinition)
if initialRef != nil && initialRef.FullDefinition == r.FullDefinition { if initialRef != nil && initialRef.FullDefinition == r.FullDefinition {
@@ -400,7 +401,7 @@ func (resolver *Resolver) isInfiniteCircularDependency(ref *Reference, visitedDe
continue continue
} }
visitedDefinitions[r.Definition] = true visitedDefinitions[r.FullDefinition] = true
ir := initialRef ir := initialRef
if ir == nil { if ir == nil {
@@ -408,6 +409,7 @@ func (resolver *Resolver) isInfiniteCircularDependency(ref *Reference, visitedDe
} }
var isChildICD bool var isChildICD bool
isChildICD, visitedDefinitions = resolver.isInfiniteCircularDependency(r, visitedDefinitions, ir) isChildICD, visitedDefinitions = resolver.isInfiniteCircularDependency(r, visitedDefinitions, ir)
if isChildICD { if isChildICD {
return true, visitedDefinitions return true, visitedDefinitions
@@ -714,8 +716,19 @@ func (resolver *Resolver) extractRelatives(ref *Reference, node, parent *yaml.No
def = fmt.Sprintf("%s#/%s", u.String(), exp[1]) def = fmt.Sprintf("%s#/%s", u.String(), exp[1])
} else { } else {
abs, _ := filepath.Abs(filepath.Join(filepath.Dir(ref.FullDefinition), exp[0])) z := strings.Split(ref.FullDefinition, "#/")
def = fmt.Sprintf("%s#/%s", abs, exp[1]) if len(z) == 2 {
if len(z[0]) > 0 {
abs, _ := filepath.Abs(filepath.Join(filepath.Dir(z[0]), exp[0]))
def = fmt.Sprintf("%s#/%s", abs, exp[1])
} else {
abs, _ := filepath.Abs(exp[0])
def = fmt.Sprintf("%s#/%s", abs, exp[1])
}
} else {
abs, _ := filepath.Abs(filepath.Join(filepath.Dir(ref.FullDefinition), exp[0]))
def = fmt.Sprintf("%s#/%s", abs, exp[1])
}
} }
} }
} else { } else {

View File

@@ -454,7 +454,7 @@ func TestResolver_ResolveComponents_Stripe_NoRolodex(t *testing.T) {
assert.NotNil(t, resolver) assert.NotNil(t, resolver)
circ := resolver.CheckForCircularReferences() circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 3) assert.Len(t, circ, 2)
_, err := yaml.Marshal(resolver.resolvedRoot) _, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err) assert.NoError(t, err)
@@ -483,8 +483,8 @@ func TestResolver_ResolveComponents_Stripe(t *testing.T) {
// after resolving, the rolodex will have errors. // after resolving, the rolodex will have errors.
rolo.Resolve() rolo.Resolve()
assert.Len(t, rolo.GetCaughtErrors(), 3) assert.Len(t, rolo.GetCaughtErrors(), 2)
assert.Len(t, rolo.GetRootIndex().GetResolver().GetNonPolymorphicCircularErrors(), 3) assert.Len(t, rolo.GetRootIndex().GetResolver().GetNonPolymorphicCircularErrors(), 2)
assert.Len(t, rolo.GetRootIndex().GetResolver().GetPolymorphicCircularErrors(), 0) assert.Len(t, rolo.GetRootIndex().GetResolver().GetPolymorphicCircularErrors(), 0)
} }
@@ -733,7 +733,7 @@ func ExampleNewResolver() {
// //
fmt.Printf("There are %d circular reference errors, %d of them are polymorphic errors, %d are not", 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())) len(circularErrors), len(resolver.GetPolymorphicCircularErrors()), len(resolver.GetNonPolymorphicCircularErrors()))
// Output: There are 3 circular reference errors, 0 of them are polymorphic errors, 3 are not // Output: There are 2 circular reference errors, 0 of them are polymorphic errors, 2 are not
} }
func ExampleResolvingError() { func ExampleResolvingError() {

View File

@@ -437,6 +437,11 @@ func (r *Rolodex) Open(location string) (RolodexFile, error) {
} }
if !isUrl { if !isUrl {
if len(r.localFS) <= 0 {
r.logger.Warn("[rolodex] no local file systems configured, cannot open local file", "location", location)
return nil, fmt.Errorf("the rolodex has no local file systems configured, cannot open local file '%s'", location)
}
for k, v := range r.localFS { for k, v := range r.localFS {
// check if this is a URL or an abs/rel reference. // check if this is a URL or an abs/rel reference.

View File

@@ -87,6 +87,7 @@ func (l *LocalFS) Open(name string) (fs.File, error) {
l.logger.Debug("[rolodex file loader]: waiting for existing OS load to complete", "file", name, "listeners", wait.listeners) l.logger.Debug("[rolodex file loader]: waiting for existing OS load to complete", "file", name, "listeners", wait.listeners)
for !wait.done { for !wait.done {
l.logger.Debug("[rolodex file loader]: sleeping for 200ns", "file", name, "listeners", wait.listeners)
time.Sleep(200 * time.Nanosecond) // breathe for a few nanoseconds. time.Sleep(200 * time.Nanosecond) // breathe for a few nanoseconds.
} }
wait.listeners-- wait.listeners--

View File

@@ -42,6 +42,17 @@ func TestRolodex_NoFS(t *testing.T) {
} }
func TestRolodex_NoFSButHasRemoteFS(t *testing.T) {
rolo := NewRolodex(CreateOpenAPIIndexConfig())
rolo.AddRemoteFS("http://localhost", nil)
rf, err := rolo.Open("spec.yaml")
assert.Error(t, err)
assert.Equal(t, "the rolodex has no local file systems configured, cannot open local file 'spec.yaml'", err.Error())
assert.Nil(t, rf)
}
func TestRolodex_LocalNativeFS(t *testing.T) { func TestRolodex_LocalNativeFS(t *testing.T) {
t.Parallel() t.Parallel()

View File

@@ -65,27 +65,27 @@ func TestSpecIndex_ExtractRefsStripe(t *testing.T) {
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Len(t, index.allRefs, 385) assert.Equal(t, 626, len(index.allRefs))
assert.Equal(t, 537, len(index.allMappedRefs)) assert.Equal(t, 871, len(index.allMappedRefs))
combined := index.GetAllCombinedReferences() combined := index.GetAllCombinedReferences()
assert.Equal(t, 537, len(combined)) assert.Equal(t, 871, len(combined))
assert.Len(t, index.rawSequencedRefs, 1972) assert.Equal(t, len(index.rawSequencedRefs), 2712)
assert.Equal(t, 246, index.pathCount) assert.Equal(t, 336, index.pathCount)
assert.Equal(t, 402, index.operationCount) assert.Equal(t, 494, index.operationCount)
assert.Equal(t, 537, index.schemaCount) assert.Equal(t, 871, index.schemaCount)
assert.Equal(t, 0, index.globalTagsCount) assert.Equal(t, 0, index.globalTagsCount)
assert.Equal(t, 0, index.globalLinksCount) assert.Equal(t, 0, index.globalLinksCount)
assert.Equal(t, 0, index.componentParamCount) assert.Equal(t, 0, index.componentParamCount)
assert.Equal(t, 143, index.operationParamCount) assert.Equal(t, 162, index.operationParamCount)
assert.Equal(t, 88, index.componentsInlineParamDuplicateCount) assert.Equal(t, 102, index.componentsInlineParamDuplicateCount)
assert.Equal(t, 55, index.componentsInlineParamUniqueCount) assert.Equal(t, 60, index.componentsInlineParamUniqueCount)
assert.Equal(t, 1516, index.enumCount) assert.Equal(t, 2579, index.enumCount)
assert.Len(t, index.GetAllEnums(), 1516) assert.Equal(t, len(index.GetAllEnums()), 2579)
assert.Len(t, index.GetPolyAllOfReferences(), 0) assert.Len(t, index.GetPolyAllOfReferences(), 0)
assert.Len(t, index.GetPolyOneOfReferences(), 275) assert.Len(t, index.GetPolyOneOfReferences(), 315)
assert.Len(t, index.GetPolyAnyOfReferences(), 553) assert.Len(t, index.GetPolyAnyOfReferences(), 708)
assert.Len(t, index.GetAllReferenceSchemas(), 1972) assert.Len(t, index.GetAllReferenceSchemas(), 2712)
assert.NotNil(t, index.GetRootServersNode()) assert.NotNil(t, index.GetRootServersNode())
assert.Len(t, index.GetAllRootServers(), 1) assert.Len(t, index.GetAllRootServers(), 1)
assert.Equal(t, "", index.GetSpecAbsolutePath()) assert.Equal(t, "", index.GetSpecAbsolutePath())
@@ -101,9 +101,9 @@ func TestSpecIndex_ExtractRefsStripe(t *testing.T) {
index.SetCircularReferences([]*CircularReferenceResult{new(CircularReferenceResult)}) index.SetCircularReferences([]*CircularReferenceResult{new(CircularReferenceResult)})
assert.Len(t, index.GetCircularReferences(), 1) assert.Len(t, index.GetCircularReferences(), 1)
assert.Len(t, index.GetRefsByLine(), 537) assert.Equal(t, 871, len(index.GetRefsByLine()))
assert.Len(t, index.GetLinesWithReferences(), 1972) assert.Equal(t, 2712, len(index.GetLinesWithReferences()), 1972)
assert.Len(t, index.GetAllExternalDocuments(), 0) assert.Equal(t, 0, len(index.GetAllExternalDocuments()))
} }
func TestSpecIndex_Asana(t *testing.T) { func TestSpecIndex_Asana(t *testing.T) {
@@ -239,7 +239,7 @@ func TestSpecIndex_DigitalOcean_FullCheckoutLocalResolve(t *testing.T) {
files := fileFS.GetFiles() files := fileFS.GetFiles()
fileLen := len(files) fileLen := len(files)
assert.Equal(t, 1691, fileLen) assert.Equal(t, 1696, fileLen)
rolo.AddLocalFS(basePath, fileFS) rolo.AddLocalFS(basePath, fileFS)
@@ -251,8 +251,8 @@ func TestSpecIndex_DigitalOcean_FullCheckoutLocalResolve(t *testing.T) {
assert.NotNil(t, index) assert.NotNil(t, index)
assert.Len(t, index.GetMappedReferencesSequenced(), 299) assert.Len(t, index.GetMappedReferencesSequenced(), 300)
assert.Len(t, index.GetMappedReferences(), 299) assert.Len(t, index.GetMappedReferences(), 300)
assert.Len(t, fileFS.GetErrors(), 0) assert.Len(t, fileFS.GetErrors(), 0)
// check circular references // check circular references
@@ -260,9 +260,9 @@ func TestSpecIndex_DigitalOcean_FullCheckoutLocalResolve(t *testing.T) {
assert.Len(t, rolo.GetCaughtErrors(), 0) assert.Len(t, rolo.GetCaughtErrors(), 0)
assert.Len(t, rolo.GetIgnoredCircularReferences(), 0) assert.Len(t, rolo.GetIgnoredCircularReferences(), 0)
assert.Equal(t, int64(1328224), rolo.RolodexFileSize()) assert.Equal(t, int64(1330184), rolo.RolodexFileSize())
assert.Equal(t, "1.27 MB", rolo.RolodexFileSizeAsString()) assert.Equal(t, "1.27 MB", rolo.RolodexFileSizeAsString())
assert.Equal(t, 1691, rolo.RolodexTotalFiles()) assert.Equal(t, 1696, rolo.RolodexTotalFiles())
} }
@@ -317,7 +317,7 @@ func TestSpecIndex_DigitalOcean_FullCheckoutLocalResolve_RecursiveLookup(t *test
files := fileFS.GetFiles() files := fileFS.GetFiles()
fileLen := len(files) fileLen := len(files)
assert.Equal(t, 1677, fileLen) assert.Equal(t, 1682, fileLen)
assert.NoError(t, rErr) assert.NoError(t, rErr)
@@ -325,8 +325,8 @@ func TestSpecIndex_DigitalOcean_FullCheckoutLocalResolve_RecursiveLookup(t *test
assert.NotNil(t, index) assert.NotNil(t, index)
assert.Len(t, index.GetMappedReferencesSequenced(), 299) assert.Len(t, index.GetMappedReferencesSequenced(), 300)
assert.Len(t, index.GetMappedReferences(), 299) assert.Len(t, index.GetMappedReferences(), 300)
assert.Len(t, fileFS.GetErrors(), 0) assert.Len(t, fileFS.GetErrors(), 0)
// check circular references // check circular references
@@ -334,9 +334,9 @@ func TestSpecIndex_DigitalOcean_FullCheckoutLocalResolve_RecursiveLookup(t *test
assert.Len(t, rolo.GetCaughtErrors(), 0) assert.Len(t, rolo.GetCaughtErrors(), 0)
assert.Len(t, rolo.GetIgnoredCircularReferences(), 0) assert.Len(t, rolo.GetIgnoredCircularReferences(), 0)
assert.Equal(t, int64(1266728), rolo.RolodexFileSize()) assert.Equal(t, int64(1270079), rolo.RolodexFileSize())
assert.Equal(t, "1.21 MB", rolo.RolodexFileSizeAsString()) assert.Equal(t, "1.21 MB", rolo.RolodexFileSizeAsString())
assert.Equal(t, 1677, rolo.RolodexTotalFiles()) assert.Equal(t, 1682, rolo.RolodexTotalFiles())
} }
@@ -1469,16 +1469,16 @@ func ExampleNewSpecIndex() {
len(index.GetAllSchemas()), len(index.GetAllSchemas()),
len(index.GetAllEnums()), len(index.GetAllEnums()),
len(index.GetPolyOneOfReferences())+len(index.GetPolyAnyOfReferences())) len(index.GetPolyOneOfReferences())+len(index.GetPolyAnyOfReferences()))
// Output: There are 537 references // Output: There are 871 references
// 246 paths // 336 paths
// 402 operations // 494 operations
// 537 component schemas // 871 component schemas
// 1972 reference schemas // 2712 reference schemas
// 11749 inline schemas // 15928 inline schemas
// 2612 inline schemas that are objects or arrays // 3857 inline schemas that are objects or arrays
// 14258 total schemas // 19511 total schemas
// 1516 enums // 2579 enums
// 828 polymorphic references // 1023 polymorphic references
} }
func TestSpecIndex_GetAllPathsHavePathAndParent(t *testing.T) { func TestSpecIndex_GetAllPathsHavePathAndParent(t *testing.T) {

View File

@@ -68,6 +68,9 @@ func (mg *MockGenerator) SetPretty() {
// The name parameter is optional, if provided, the mock generator will attempt to find an example with the given name. // The name parameter is optional, if provided, the mock generator will attempt to find an example with the given name.
// If no name is provided, the first example will be used. // If no name is provided, the first example will be used.
func (mg *MockGenerator) GenerateMock(mock any, name string) ([]byte, error) { func (mg *MockGenerator) GenerateMock(mock any, name string) ([]byte, error) {
if mock == nil || !reflect.ValueOf(mock).IsValid() || reflect.ValueOf(mock).IsNil() {
return nil, nil
}
v := reflect.ValueOf(mock).Elem() v := reflect.ValueOf(mock).Elem()
num := v.NumField() num := v.NumField()
fieldCount := 0 fieldCount := 0

View File

@@ -99,6 +99,18 @@ func TestNewMockGeneratorWithDictionary(t *testing.T) {
assert.NotNil(t, mg) assert.NotNil(t, mg)
} }
func TestMockGenerator_GenerateJSONMock_NoObject(t *testing.T) {
mg := NewMockGenerator(JSON)
var isNil any
isNil = nil
mock, err := mg.GenerateMock(isNil, "")
assert.NoError(t, err)
assert.Nil(t, mock)
}
func TestMockGenerator_GenerateJSONMock_BadObject(t *testing.T) { func TestMockGenerator_GenerateJSONMock_BadObject(t *testing.T) {
type NotMockable struct { type NotMockable struct {
pizza string pizza string

81630
test_specs/stripe-old.yaml Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -107,6 +107,38 @@ biscuit:
assert.Equal(t, 1, extChanges.TotalBreakingChanges()) assert.Equal(t, 1, extChanges.TotalBreakingChanges())
} }
// codecov seems to get upset with this not being covered.
// so lets run the damn thing a few hundred thousand times.
func BenchmarkCompareSecurityRequirement_Remove(b *testing.B) {
left := `auth:
- pizza
- pie`
right := `auth:
- pie
- pizza
biscuit:
- digestive`
var lNode, rNode yaml.Node
_ = yaml.Unmarshal([]byte(left), &lNode)
_ = yaml.Unmarshal([]byte(right), &rNode)
for i := 0; i < b.N; i++ {
var lDoc base.SecurityRequirement
var rDoc base.SecurityRequirement
_ = low.BuildModel(lNode.Content[0], &lDoc)
_ = low.BuildModel(rNode.Content[0], &rDoc)
_ = lDoc.Build(context.Background(), nil, lNode.Content[0], nil)
_ = rDoc.Build(context.Background(), nil, rNode.Content[0], nil)
extChanges := CompareSecurityRequirement(&rDoc, &lDoc)
assert.Equal(b, 1, extChanges.TotalChanges())
assert.Len(b, extChanges.GetAllChanges(), 1)
assert.Equal(b, 1, extChanges.TotalBreakingChanges())
}
}
func TestCompareSecurityRequirement_SwapOut_V2(t *testing.T) { func TestCompareSecurityRequirement_SwapOut_V2(t *testing.T) {
left := `cheese: left := `cheese: