Skip to content

Commit cda65e2

Browse files
committed
more model refactoring and cleanup.
1 parent 10828ca commit cda65e2

24 files changed

+1409
-257
lines changed
Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
// Copyright 2022-2026 Princess B33f Heavy Industries / Dave Shanley
2+
// SPDX-License-Identifier: MIT
3+
4+
package base
5+
6+
import (
7+
"context"
8+
"testing"
9+
10+
"github.com/pb33f/libopenapi/datamodel/low"
11+
"github.com/pb33f/libopenapi/index"
12+
"go.yaml.in/yaml/v4"
13+
)
14+
15+
func benchmarkInfoRootNode(b *testing.B) *yaml.Node {
16+
b.Helper()
17+
18+
yml := `title: Pizza API
19+
summary: pizza summary
20+
description: pizza description
21+
termsOfService: https://example.com/tos
22+
contact:
23+
name: Pizza Team
24+
url: https://example.com/contact
25+
email: pizza@example.com
26+
license:
27+
name: MIT
28+
url: https://example.com/license
29+
version: 1.0.0
30+
x-info:
31+
hot: true`
32+
33+
var root yaml.Node
34+
if err := yaml.Unmarshal([]byte(yml), &root); err != nil {
35+
b.Fatalf("failed to unmarshal benchmark info: %v", err)
36+
}
37+
if len(root.Content) == 0 || root.Content[0] == nil {
38+
b.Fatal("failed to unmarshal benchmark info: empty root")
39+
}
40+
return root.Content[0]
41+
}
42+
43+
func benchmarkContactRootNode(b *testing.B) *yaml.Node {
44+
b.Helper()
45+
46+
yml := `name: Pizza Team
47+
url: https://example.com/contact
48+
email: pizza@example.com
49+
x-contact:
50+
warm: true`
51+
52+
var root yaml.Node
53+
if err := yaml.Unmarshal([]byte(yml), &root); err != nil {
54+
b.Fatalf("failed to unmarshal benchmark contact: %v", err)
55+
}
56+
if len(root.Content) == 0 || root.Content[0] == nil {
57+
b.Fatal("failed to unmarshal benchmark contact: empty root")
58+
}
59+
return root.Content[0]
60+
}
61+
62+
func benchmarkLicenseRootNode(b *testing.B) *yaml.Node {
63+
b.Helper()
64+
65+
yml := `name: Apache-2.0
66+
url: https://example.com/license
67+
x-license:
68+
approved: true`
69+
70+
var root yaml.Node
71+
if err := yaml.Unmarshal([]byte(yml), &root); err != nil {
72+
b.Fatalf("failed to unmarshal benchmark license: %v", err)
73+
}
74+
if len(root.Content) == 0 || root.Content[0] == nil {
75+
b.Fatal("failed to unmarshal benchmark license: empty root")
76+
}
77+
return root.Content[0]
78+
}
79+
80+
func benchmarkExternalDocRootNode(b *testing.B) *yaml.Node {
81+
b.Helper()
82+
83+
yml := `description: more docs
84+
url: https://example.com/docs
85+
x-docs:
86+
bright: true`
87+
88+
var root yaml.Node
89+
if err := yaml.Unmarshal([]byte(yml), &root); err != nil {
90+
b.Fatalf("failed to unmarshal benchmark external doc: %v", err)
91+
}
92+
if len(root.Content) == 0 || root.Content[0] == nil {
93+
b.Fatal("failed to unmarshal benchmark external doc: empty root")
94+
}
95+
return root.Content[0]
96+
}
97+
98+
func benchmarkXMLRootNode(b *testing.B) *yaml.Node {
99+
b.Helper()
100+
101+
yml := `name: item
102+
namespace: https://example.com/ns
103+
prefix: ex
104+
attribute: false
105+
nodeType: element
106+
wrapped: true
107+
x-xml:
108+
rich: true`
109+
110+
var root yaml.Node
111+
if err := yaml.Unmarshal([]byte(yml), &root); err != nil {
112+
b.Fatalf("failed to unmarshal benchmark xml: %v", err)
113+
}
114+
if len(root.Content) == 0 || root.Content[0] == nil {
115+
b.Fatal("failed to unmarshal benchmark xml: empty root")
116+
}
117+
return root.Content[0]
118+
}
119+
120+
func benchmarkSecurityRequirementRootNode(b *testing.B) *yaml.Node {
121+
b.Helper()
122+
123+
yml := `oauth:
124+
- read
125+
- write
126+
apiKey:
127+
- admin`
128+
129+
var root yaml.Node
130+
if err := yaml.Unmarshal([]byte(yml), &root); err != nil {
131+
b.Fatalf("failed to unmarshal benchmark security requirement: %v", err)
132+
}
133+
if len(root.Content) == 0 || root.Content[0] == nil {
134+
b.Fatal("failed to unmarshal benchmark security requirement: empty root")
135+
}
136+
return root.Content[0]
137+
}
138+
139+
func benchmarkTagRootNode(b *testing.B) *yaml.Node {
140+
b.Helper()
141+
142+
yml := `name: partner
143+
summary: Partner API
144+
description: Operations available to the partners network
145+
parent: external
146+
kind: audience
147+
externalDocs:
148+
url: https://example.com/docs
149+
description: more docs
150+
x-tag:
151+
warm: true`
152+
153+
var root yaml.Node
154+
if err := yaml.Unmarshal([]byte(yml), &root); err != nil {
155+
b.Fatalf("failed to unmarshal benchmark tag: %v", err)
156+
}
157+
if len(root.Content) == 0 || root.Content[0] == nil {
158+
b.Fatal("failed to unmarshal benchmark tag: empty root")
159+
}
160+
return root.Content[0]
161+
}
162+
163+
func BenchmarkInfo_Build(b *testing.B) {
164+
rootNode := benchmarkInfoRootNode(b)
165+
idx := index.NewSpecIndex(rootNode)
166+
ctx := context.Background()
167+
168+
b.ReportAllocs()
169+
b.ResetTimer()
170+
171+
for i := 0; i < b.N; i++ {
172+
var info Info
173+
if err := low.BuildModel(rootNode, &info); err != nil {
174+
b.Fatalf("build model failed: %v", err)
175+
}
176+
if err := info.Build(ctx, nil, rootNode, idx); err != nil {
177+
b.Fatalf("info build failed: %v", err)
178+
}
179+
}
180+
}
181+
182+
func BenchmarkContact_Build(b *testing.B) {
183+
rootNode := benchmarkContactRootNode(b)
184+
idx := index.NewSpecIndex(rootNode)
185+
ctx := context.Background()
186+
187+
b.ReportAllocs()
188+
b.ResetTimer()
189+
190+
for i := 0; i < b.N; i++ {
191+
var contact Contact
192+
if err := low.BuildModel(rootNode, &contact); err != nil {
193+
b.Fatalf("build model failed: %v", err)
194+
}
195+
if err := contact.Build(ctx, nil, rootNode, idx); err != nil {
196+
b.Fatalf("contact build failed: %v", err)
197+
}
198+
}
199+
}
200+
201+
func BenchmarkLicense_Build(b *testing.B) {
202+
rootNode := benchmarkLicenseRootNode(b)
203+
idx := index.NewSpecIndex(rootNode)
204+
ctx := context.Background()
205+
206+
b.ReportAllocs()
207+
b.ResetTimer()
208+
209+
for i := 0; i < b.N; i++ {
210+
var license License
211+
if err := low.BuildModel(rootNode, &license); err != nil {
212+
b.Fatalf("build model failed: %v", err)
213+
}
214+
if err := license.Build(ctx, nil, rootNode, idx); err != nil {
215+
b.Fatalf("license build failed: %v", err)
216+
}
217+
}
218+
}
219+
220+
func BenchmarkExternalDoc_Build(b *testing.B) {
221+
rootNode := benchmarkExternalDocRootNode(b)
222+
idx := index.NewSpecIndex(rootNode)
223+
ctx := context.Background()
224+
225+
b.ReportAllocs()
226+
b.ResetTimer()
227+
228+
for i := 0; i < b.N; i++ {
229+
var ex ExternalDoc
230+
if err := low.BuildModel(rootNode, &ex); err != nil {
231+
b.Fatalf("build model failed: %v", err)
232+
}
233+
if err := ex.Build(ctx, nil, rootNode, idx); err != nil {
234+
b.Fatalf("external doc build failed: %v", err)
235+
}
236+
}
237+
}
238+
239+
func BenchmarkXML_Build(b *testing.B) {
240+
rootNode := benchmarkXMLRootNode(b)
241+
idx := index.NewSpecIndex(rootNode)
242+
243+
b.ReportAllocs()
244+
b.ResetTimer()
245+
246+
for i := 0; i < b.N; i++ {
247+
var x XML
248+
if err := low.BuildModel(rootNode, &x); err != nil {
249+
b.Fatalf("build model failed: %v", err)
250+
}
251+
if err := x.Build(rootNode, idx); err != nil {
252+
b.Fatalf("xml build failed: %v", err)
253+
}
254+
}
255+
}
256+
257+
func BenchmarkSecurityRequirement_Build(b *testing.B) {
258+
rootNode := benchmarkSecurityRequirementRootNode(b)
259+
ctx := context.Background()
260+
261+
b.ReportAllocs()
262+
b.ResetTimer()
263+
264+
for i := 0; i < b.N; i++ {
265+
var req SecurityRequirement
266+
if err := req.Build(ctx, nil, rootNode, nil); err != nil {
267+
b.Fatalf("security requirement build failed: %v", err)
268+
}
269+
}
270+
}
271+
272+
func BenchmarkTag_Build(b *testing.B) {
273+
rootNode := benchmarkTagRootNode(b)
274+
idx := index.NewSpecIndex(rootNode)
275+
ctx := context.Background()
276+
277+
b.ReportAllocs()
278+
b.ResetTimer()
279+
280+
for i := 0; i < b.N; i++ {
281+
var tag Tag
282+
if err := low.BuildModel(rootNode, &tag); err != nil {
283+
b.Fatalf("build model failed: %v", err)
284+
}
285+
if err := tag.Build(ctx, nil, rootNode, idx); err != nil {
286+
b.Fatalf("tag build failed: %v", err)
287+
}
288+
}
289+
}

datamodel/low/base/contact.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
1+
// Copyright 2022-2026 Princess B33f Heavy Industries / Dave Shanley
22
// SPDX-License-Identifier: MIT
33

44
package base
55

66
import (
77
"context"
88
"hash/maphash"
9+
"sync"
910

1011
"github.com/pb33f/libopenapi/datamodel/low"
1112
"github.com/pb33f/libopenapi/index"
@@ -26,15 +27,30 @@ type Contact struct {
2627
RootNode *yaml.Node
2728
index *index.SpecIndex
2829
context context.Context
30+
nodeStore sync.Map
31+
reference low.Reference
2932
*low.Reference
3033
low.NodeMap
3134
}
3235

3336
func (c *Contact) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.SpecIndex) error {
3437
c.KeyNode = keyNode
3538
c.RootNode = root
36-
c.Reference = new(low.Reference)
37-
c.Nodes = low.ExtractNodes(ctx, root)
39+
c.reference = low.Reference{}
40+
c.Reference = &c.reference
41+
c.nodeStore = sync.Map{}
42+
c.Nodes = &c.nodeStore
43+
if root == nil {
44+
c.Extensions = nil
45+
c.context = ctx
46+
c.index = idx
47+
return nil
48+
}
49+
if len(root.Content) > 0 {
50+
c.NodeMap.ExtractNodes(root, false)
51+
} else {
52+
c.AddNode(root.Line, root)
53+
}
3854
c.Extensions = low.ExtractExtensions(root)
3955
c.context = ctx
4056
c.index = idx

datamodel/low/base/contact_test.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
1+
// Copyright 2022-2026 Princess B33f Heavy Industries / Dave Shanley
22
// SPDX-License-Identifier: MIT
33

44
package base
@@ -44,3 +44,19 @@ x-beer: cold`
4444
assert.Nil(t, c.GetIndex())
4545
assert.NotNil(t, c.GetContext())
4646
}
47+
48+
func TestContact_Build_ScalarRoot(t *testing.T) {
49+
var scalar yaml.Node
50+
_ = yaml.Unmarshal([]byte("hello"), &scalar)
51+
52+
var c Contact
53+
err := low.BuildModel(scalar.Content[0], &c)
54+
assert.NoError(t, err)
55+
56+
err = c.Build(context.Background(), nil, scalar.Content[0], nil)
57+
assert.NoError(t, err)
58+
59+
nodes := c.GetNodes()
60+
assert.Len(t, nodes[scalar.Content[0].Line], 1)
61+
assert.Equal(t, "hello", nodes[scalar.Content[0].Line][0].Value)
62+
}

0 commit comments

Comments
 (0)