diff --git a/cmd/openapi/go.mod b/cmd/openapi/go.mod index a03e0013..d554dc8b 100644 --- a/cmd/openapi/go.mod +++ b/cmd/openapi/go.mod @@ -16,7 +16,7 @@ require ( require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/blackwell-systems/gcf-go v1.5.0 // indirect + github.com/blackwell-systems/gcf-go v1.7.1 // indirect github.com/charmbracelet/colorprofile v0.4.1 // indirect github.com/charmbracelet/x/ansi v0.11.6 // indirect github.com/charmbracelet/x/cellbuf v0.0.15 // indirect diff --git a/cmd/openapi/go.sum b/cmd/openapi/go.sum index 6f2e031b..3b57ff4d 100644 --- a/cmd/openapi/go.sum +++ b/cmd/openapi/go.sum @@ -4,8 +4,8 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/blackwell-systems/gcf-go v1.5.0 h1:ZOWyxvRF1TZOmzPYXVO1dOTU6VRslNaJgnzSDDh8hL4= -github.com/blackwell-systems/gcf-go v1.5.0/go.mod h1:hYxLOn6JHzNNNH7wfgRXWETX2lMtRtjG8FEX45I6SAI= +github.com/blackwell-systems/gcf-go v1.7.1 h1:hpdCf/GHXS/CrsXsHnnIw6hXBHhtC2dopGOdiFMnsc4= +github.com/blackwell-systems/gcf-go v1.7.1/go.mod h1:hYxLOn6JHzNNNH7wfgRXWETX2lMtRtjG8FEX45I6SAI= github.com/charmbracelet/bubbles v1.0.0 h1:12J8/ak/uCZEMQ6KU7pcfwceyjLlWsDLAxB5fXonfvc= github.com/charmbracelet/bubbles v1.0.0/go.mod h1:9d/Zd5GdnauMI5ivUIVisuEm3ave1XwXtD1ckyV6r3E= github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= diff --git a/go.mod b/go.mod index d7086a46..f22768f6 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/speakeasy-api/openapi go 1.25.0 require ( - github.com/blackwell-systems/gcf-go v1.5.0 + github.com/blackwell-systems/gcf-go v1.7.1 github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 github.com/speakeasy-api/jsonpath v0.6.3 github.com/stretchr/testify v1.11.1 diff --git a/go.sum b/go.sum index 60c70359..3d1feaa9 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/blackwell-systems/gcf-go v1.5.0 h1:ZOWyxvRF1TZOmzPYXVO1dOTU6VRslNaJgnzSDDh8hL4= -github.com/blackwell-systems/gcf-go v1.5.0/go.mod h1:hYxLOn6JHzNNNH7wfgRXWETX2lMtRtjG8FEX45I6SAI= +github.com/blackwell-systems/gcf-go v1.7.1 h1:hpdCf/GHXS/CrsXsHnnIw6hXBHhtC2dopGOdiFMnsc4= +github.com/blackwell-systems/gcf-go v1.7.1/go.mod h1:hYxLOn6JHzNNNH7wfgRXWETX2lMtRtjG8FEX45I6SAI= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/oq/format_test.go b/oq/format_test.go index 3f8653ec..2ebbfdc4 100644 --- a/oq/format_test.go +++ b/oq/format_test.go @@ -16,3 +16,56 @@ func TestToonValue_ArrayEscapesSemicolonElements(t *testing.T) { assert.Equal(t, `"v1;deprecated";"v2;current"`, encoded, "array elements containing the delimiter should be quoted individually") } + +// TestFormatGCF_ArrayValuedProjection pins the GCF output for a projection that +// includes an array-valued field. FormatGCF passes array fields to the encoder as +// []string, which are emitted as a GCF array attachment (a "^" marker on the row +// plus a ".scopes [N]: ..." continuation line) rather than a single scalar cell. +// This golden covers the array path that the default petstore smoke query does not +// exercise (its operation fields contain no arrays). +func TestFormatGCF_ArrayValuedProjection(t *testing.T) { + t.Parallel() + + // SecurityRequirement rows read schemeName/scopes directly off the Row, so this + // drives FormatGCF end to end without needing a populated SchemaGraph. + result := &Result{ + Rows: []Row{{ + Kind: SecurityRequirementResult, + SchemeName: "petstore_auth", + Scopes: []string{"read:pets", "write:pets"}, + }}, + Fields: []string{"schemeName", "scopes"}, + } + + got := FormatGCF(result, nil) + + want := "GCF profile=generic\n" + + "## [1]{schemeName,scopes}\n" + + "@0 petstore_auth|^\n" + + ".scopes [2]: read:pets,write:pets\n" + assert.Equal(t, want, got, "array-valued fields should emit as a GCF array attachment") +} + +// TestFormatGCF_MarkerShapedStringQuoted pins the GCF output for a string value +// shaped like a GCF marker ("^{...}"). Such values are quoted rather than emitted +// bare so they round-trip as literal strings instead of being read as markup. +func TestFormatGCF_MarkerShapedStringQuoted(t *testing.T) { + t.Parallel() + + result := &Result{ + Rows: []Row{{ + Kind: SecurityRequirementResult, + SchemeName: "^{oauth}", + Scopes: []string{"read"}, + }}, + Fields: []string{"schemeName", "scopes"}, + } + + got := FormatGCF(result, nil) + + want := "GCF profile=generic\n" + + "## [1]{schemeName,scopes}\n" + + "@0 \"^{oauth}\"|^\n" + + ".scopes [1]: read\n" + assert.Equal(t, want, got, "marker-shaped string values should be quoted") +}