From 76c7b491f65659300a6ebd1ebe8bbdc9af24cc08 Mon Sep 17 00:00:00 2001 From: kriptoburak Date: Thu, 2 Jul 2026 17:41:26 +0300 Subject: [PATCH 1/2] Add Xquik OpenAPI 3.1 parse fixture --- examples/v3.1/yaml/xquik.yaml | 63 +++++++++++++++++++++++++++++++++++ openapiv3/openapiv3_test.go | 29 ++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 examples/v3.1/yaml/xquik.yaml diff --git a/examples/v3.1/yaml/xquik.yaml b/examples/v3.1/yaml/xquik.yaml new file mode 100644 index 00000000..f11c8b56 --- /dev/null +++ b/examples/v3.1/yaml/xquik.yaml @@ -0,0 +1,63 @@ +openapi: 3.1.0 +info: + title: Xquik API + version: "1.0" +servers: + - url: https://xquik.com +security: + - apiKey: [] +paths: + /api/v1/x/tweets/search: + get: + operationId: searchTweets + summary: Search X posts + parameters: + - name: q + in: query + required: true + schema: + type: string + - name: limit + in: query + schema: + type: integer + minimum: 1 + maximum: 100 + responses: + "200": + description: Search results + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + type: array + items: + $ref: "#/components/schemas/Tweet" +components: + securitySchemes: + apiKey: + type: apiKey + in: header + name: x-api-key + schemas: + Tweet: + type: object + required: + - id + - text + - authorHandle + - createdAt + properties: + id: + type: string + text: + type: string + authorHandle: + type: string + createdAt: + type: string + format: date-time diff --git a/openapiv3/openapiv3_test.go b/openapiv3/openapiv3_test.go index 621cab51..961b723b 100644 --- a/openapiv3/openapiv3_test.go +++ b/openapiv3/openapiv3_test.go @@ -37,6 +37,35 @@ func TestParseDocument(t *testing.T) { } } +func TestParseDocument_XquikOpenAPI31(t *testing.T) { + filename := "../examples/v3.1/yaml/xquik.yaml" + b, err := ioutil.ReadFile(filename) + if err != nil { + t.Logf("unable to read file %s", filename) + t.FailNow() + } + d, err := ParseDocument(b) + if err != nil { + t.Logf("%s", err.Error()) + t.FailNow() + } + if d.Info.Title != "Xquik API" { + t.Errorf("unexpected value for Title: %s", d.Info.Title) + } + if !documentHasPath(d, "/api/v1/x/tweets/search") { + t.Errorf("missing Xquik search path") + } +} + +func documentHasPath(document *Document, name string) bool { + for _, path := range document.Paths.Path { + if path.Name == name { + return true + } + } + return false +} + func TestParseDocument_Empty(t *testing.T) { for _, test := range []struct { name string From a715a5f08be87c3cab96be2a8035b6ea5cd3184c Mon Sep 17 00:00:00 2001 From: kriptoburak Date: Sun, 19 Jul 2026 04:26:13 +0300 Subject: [PATCH 2/2] Fix JSON object key escaping --- jsonwriter/writer.go | 4 +++- jsonwriter/writer_test.go | 12 ++++++++++++ openapiv3/openapiv3_test.go | 6 +++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/jsonwriter/writer.go b/jsonwriter/writer.go index 675c8ce8..cff7689c 100644 --- a/jsonwriter/writer.go +++ b/jsonwriter/writer.go @@ -54,7 +54,9 @@ func (w *writer) writeMap(node *yaml.Node, indent string) { for i := 0; i < len(node.Content); i += 2 { // first print the key key := node.Content[i].Value - w.writeString(fmt.Sprintf("%s\"%+v\": ", innerIndent, key)) + w.writeString(innerIndent) + w.writeString(strconv.Quote(key)) + w.writeString(": ") // then the value value := node.Content[i+1] switch value.Kind { diff --git a/jsonwriter/writer_test.go b/jsonwriter/writer_test.go index bed88a16..5ea9136a 100644 --- a/jsonwriter/writer_test.go +++ b/jsonwriter/writer_test.go @@ -46,6 +46,7 @@ func TestMarshal(t *testing.T) { sequenceSequenceStringArrayTestCase(), sequenceMappingNodeTestCase(), mappingNodeTestCase(), + mappingNodeEscapedKeyTestCase(), documentNodeTestCase(), aliasNodeTestCase(), } @@ -193,6 +194,17 @@ func mappingNodeTestCase() *MarshalTestCase { } } +func mappingNodeEscapedKeyTestCase() *MarshalTestCase { + node := compiler.NewMappingNode() + node.Content = append(node.Content, compiler.NewScalarNodeForString("a\\b\nc\"")) + node.Content = append(node.Content, compiler.NewScalarNodeForString("value")) + return &MarshalTestCase{ + Name: "Mapping node with escaped key", + Node: node, + Expected: "{\n \"a\\\\b\\nc\\\"\": \"value\"\n}\n", + } +} + func documentNodeTestCase() *MarshalTestCase { m := compiler.NewMappingNode() m.Content = append(m.Content, compiler.NewScalarNodeForString("version")) diff --git a/openapiv3/openapiv3_test.go b/openapiv3/openapiv3_test.go index 961b723b..cc15eefe 100644 --- a/openapiv3/openapiv3_test.go +++ b/openapiv3/openapiv3_test.go @@ -15,13 +15,13 @@ package openapi_v3 import ( - "io/ioutil" + "os" "testing" ) func TestParseDocument(t *testing.T) { filename := "../examples/v3.0/yaml/petstore.yaml" - b, err := ioutil.ReadFile(filename) + b, err := os.ReadFile(filename) if err != nil { t.Logf("unable to read file %s", filename) t.FailNow() @@ -39,7 +39,7 @@ func TestParseDocument(t *testing.T) { func TestParseDocument_XquikOpenAPI31(t *testing.T) { filename := "../examples/v3.1/yaml/xquik.yaml" - b, err := ioutil.ReadFile(filename) + b, err := os.ReadFile(filename) if err != nil { t.Logf("unable to read file %s", filename) t.FailNow()