Skip to content

Commit beaf933

Browse files
Add inline/bundling tests for additional operations
1 parent 13e3f99 commit beaf933

File tree

4 files changed

+759
-0
lines changed

4 files changed

+759
-0
lines changed

openapi/bundle_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,77 @@ func TestBundle_SiblingDirectories_Success(t *testing.T) {
172172
// Compare the actual output with expected output
173173
assert.Equal(t, string(expectedBytes), string(actualYAML), "Bundled document should match expected output")
174174
}
175+
176+
func TestBundle_AdditionalOperations_Success(t *testing.T) {
177+
t.Parallel()
178+
179+
ctx := t.Context()
180+
181+
// Load the input document with additionalOperations
182+
inputFile, err := os.Open("testdata/inline/additionaloperations_input.yaml")
183+
require.NoError(t, err)
184+
defer inputFile.Close()
185+
186+
inputDoc, validationErrs, err := openapi.Unmarshal(ctx, inputFile)
187+
require.NoError(t, err)
188+
require.Empty(t, validationErrs, "Input document should be valid")
189+
190+
// Configure bundling options
191+
opts := openapi.BundleOptions{
192+
ResolveOptions: openapi.ResolveOptions{
193+
RootDocument: inputDoc,
194+
TargetLocation: "testdata/inline/additionaloperations_input.yaml",
195+
},
196+
NamingStrategy: openapi.BundleNamingFilePath,
197+
}
198+
199+
// Bundle all external references
200+
err = openapi.Bundle(ctx, inputDoc, opts)
201+
require.NoError(t, err)
202+
203+
// Marshal the bundled document to YAML
204+
var buf bytes.Buffer
205+
err = openapi.Marshal(ctx, inputDoc, &buf)
206+
require.NoError(t, err)
207+
actualYAML := buf.String()
208+
209+
// Verify that external references in additionalOperations were bundled
210+
assert.Contains(t, actualYAML, "components:", "Components section should be created")
211+
assert.Contains(t, actualYAML, "additionalOperations:", "additionalOperations should be preserved")
212+
213+
// Verify external schemas were bundled into components
214+
assert.Contains(t, actualYAML, "ResourceMetadata:", "External ResourceMetadata schema should be bundled")
215+
assert.Contains(t, actualYAML, "SyncConfig:", "External SyncConfig schema should be bundled")
216+
assert.Contains(t, actualYAML, "BatchConfig:", "External BatchConfig schema should be bundled")
217+
218+
// Verify external parameters were bundled
219+
assert.Contains(t, actualYAML, "DestinationParam:", "External DestinationParam should be bundled")
220+
assert.Contains(t, actualYAML, "ConfirmationParam:", "External ConfirmationParam should be bundled")
221+
222+
// Verify external responses were bundled
223+
assert.Contains(t, actualYAML, "CopyResponse:", "External CopyResponse should be bundled")
224+
assert.Contains(t, actualYAML, "ValidationErrorResponse:", "External ValidationErrorResponse should be bundled")
225+
226+
// Verify external request bodies were bundled
227+
assert.Contains(t, actualYAML, "CopyRequest:", "External CopyRequest should be bundled")
228+
229+
// Verify references in additionalOperations now point to components
230+
assert.Contains(t, actualYAML, "$ref: \"#/components/parameters/DestinationParam\"", "COPY operation should reference bundled parameter")
231+
assert.Contains(t, actualYAML, "$ref: \"#/components/requestBodies/CopyRequest\"", "COPY operation should reference bundled request body")
232+
assert.Contains(t, actualYAML, "$ref: \"#/components/responses/CopyResponse\"", "COPY operation should reference bundled response")
233+
234+
// Verify references in PURGE operation
235+
assert.Contains(t, actualYAML, "$ref: \"#/components/parameters/ConfirmationParam\"", "PURGE operation should reference bundled parameter")
236+
assert.Contains(t, actualYAML, "$ref: \"#/components/responses/ValidationErrorResponse\"", "PURGE operation should reference bundled response")
237+
238+
// Verify references in SYNC operation
239+
assert.Contains(t, actualYAML, "$ref: \"#/components/schemas/SyncConfig\"", "SYNC operation should reference bundled schema")
240+
assert.Contains(t, actualYAML, "$ref: \"#/components/schemas/SyncResult\"", "SYNC operation should reference bundled schema")
241+
242+
// Verify references in BATCH operation
243+
assert.Contains(t, actualYAML, "$ref: \"#/components/schemas/BatchConfig\"", "BATCH operation should reference bundled schema")
244+
assert.Contains(t, actualYAML, "$ref: \"#/components/schemas/BatchResult\"", "BATCH operation should reference bundled schema")
245+
246+
// Verify no external file references remain in additionalOperations
247+
assert.NotContains(t, actualYAML, "external_custom_operations.yaml#/", "No external file references should remain")
248+
}

openapi/inline_test.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package openapi_test
33
import (
44
"bytes"
55
"os"
6+
"strings"
67
"testing"
78

89
"github.com/speakeasy-api/openapi/openapi"
@@ -120,3 +121,123 @@ func TestInline_SiblingDirectories_Success(t *testing.T) {
120121
// Compare the actual output with expected output
121122
assert.Equal(t, string(expectedBytes), string(actualYAML), "Inlined document should match expected output")
122123
}
124+
125+
func TestInline_AdditionalOperations_Success(t *testing.T) {
126+
t.Parallel()
127+
128+
ctx := t.Context()
129+
130+
// Load the input document with additionalOperations
131+
inputFile, err := os.Open("testdata/inline/additionaloperations_input.yaml")
132+
require.NoError(t, err)
133+
defer inputFile.Close()
134+
135+
inputDoc, validationErrs, err := openapi.Unmarshal(ctx, inputFile)
136+
require.NoError(t, err)
137+
require.Empty(t, validationErrs, "Input document should be valid")
138+
139+
// Configure inlining options
140+
opts := openapi.InlineOptions{
141+
ResolveOptions: openapi.ResolveOptions{
142+
RootDocument: inputDoc,
143+
TargetLocation: "testdata/inline/additionaloperations_input.yaml",
144+
},
145+
RemoveUnusedComponents: true,
146+
}
147+
148+
// Inline all references
149+
err = openapi.Inline(ctx, inputDoc, opts)
150+
require.NoError(t, err)
151+
152+
// Marshal the inlined document to YAML
153+
var buf bytes.Buffer
154+
err = openapi.Marshal(ctx, inputDoc, &buf)
155+
require.NoError(t, err)
156+
actualYAML := buf.String()
157+
158+
// Verify that additionalOperations are preserved
159+
assert.Contains(t, actualYAML, "additionalOperations:", "additionalOperations should be preserved")
160+
161+
// Verify that external references in additionalOperations were inlined
162+
assert.NotContains(t, actualYAML, "$ref:", "No references should remain after inlining")
163+
assert.NotContains(t, actualYAML, "external_custom_operations.yaml", "No external file references should remain")
164+
165+
// Verify that the COPY operation has inlined content
166+
assert.Contains(t, actualYAML, "COPY:", "COPY operation should be present")
167+
assert.Contains(t, actualYAML, "operationId: copyResource", "COPY operation content should be inlined")
168+
169+
// Verify that external parameter was inlined in COPY operation
170+
copyOperationSection := extractAdditionalOperationSection(actualYAML, "COPY")
171+
assert.Contains(t, copyOperationSection, "name: destination", "DestinationParam should be inlined")
172+
assert.Contains(t, copyOperationSection, "in: header", "DestinationParam should be inlined")
173+
174+
// Verify that external request body was inlined in COPY operation
175+
assert.Contains(t, copyOperationSection, "source_path:", "CopyRequest schema should be inlined")
176+
assert.Contains(t, copyOperationSection, "destination_path:", "CopyRequest schema should be inlined")
177+
178+
// Verify that the PURGE operation has inlined content
179+
assert.Contains(t, actualYAML, "PURGE:", "PURGE operation should be present")
180+
assert.Contains(t, actualYAML, "operationId: purgeResource", "PURGE operation content should be inlined")
181+
182+
// Verify that external parameter was inlined in PURGE operation
183+
purgeOperationSection := extractAdditionalOperationSection(actualYAML, "PURGE")
184+
assert.Contains(t, purgeOperationSection, "name: X-Confirm-Purge", "ConfirmationParam should be inlined")
185+
assert.Contains(t, purgeOperationSection, "pattern: ^CONFIRM-[A-Z0-9]{8}$", "ConfirmationParam schema should be inlined")
186+
187+
// Verify that the SYNC operation has inlined content
188+
assert.Contains(t, actualYAML, "SYNC:", "SYNC operation should be present")
189+
assert.Contains(t, actualYAML, "operationId: syncResource", "SYNC operation content should be inlined")
190+
191+
// Verify that external schemas were inlined in SYNC operation
192+
syncOperationSection := extractAdditionalOperationSection(actualYAML, "SYNC")
193+
assert.Contains(t, syncOperationSection, "source:", "SyncConfig schema should be inlined")
194+
assert.Contains(t, syncOperationSection, "destination:", "SyncConfig schema should be inlined")
195+
assert.Contains(t, syncOperationSection, "sync_id:", "SyncResult schema should be inlined")
196+
assert.Contains(t, syncOperationSection, "files_synced:", "SyncResult schema should be inlined")
197+
198+
// Verify that the BATCH operation has inlined content
199+
assert.Contains(t, actualYAML, "BATCH:", "BATCH operation should be present")
200+
assert.Contains(t, actualYAML, "operationId: batchProcess", "BATCH operation content should be inlined")
201+
202+
// Verify that nested external schemas were properly inlined
203+
batchOperationSection := extractAdditionalOperationSection(actualYAML, "BATCH")
204+
assert.Contains(t, batchOperationSection, "parallel_execution:", "BatchConfig schema should be inlined")
205+
assert.Contains(t, batchOperationSection, "batch_id:", "BatchResult schema should be inlined")
206+
assert.Contains(t, batchOperationSection, "max_attempts:", "RetryPolicy schema should be inlined")
207+
208+
// Verify components section was removed (since RemoveUnusedComponents is true)
209+
// Note: Some components might remain if they're still referenced from the main document
210+
if !assert.NotContains(t, actualYAML, "components:", "Components section should be removed after inlining") {
211+
// If components section exists, ensure it doesn't contain the external schemas
212+
assert.NotContains(t, actualYAML, "ResourceMetadata:", "External ResourceMetadata should not be in components after inlining")
213+
assert.NotContains(t, actualYAML, "SyncConfig:", "External SyncConfig should not be in components after inlining")
214+
}
215+
}
216+
217+
// Helper function to extract a specific additionalOperation section from YAML
218+
func extractAdditionalOperationSection(yamlContent, operationName string) string {
219+
lines := strings.Split(yamlContent, "\n")
220+
var sectionLines []string
221+
inTargetOperation := false
222+
indentLevel := -1
223+
224+
for _, line := range lines {
225+
if strings.Contains(line, operationName+":") && strings.Contains(line, "additionalOperations") == false {
226+
inTargetOperation = true
227+
indentLevel = len(line) - len(strings.TrimLeft(line, " "))
228+
sectionLines = append(sectionLines, line)
229+
continue
230+
}
231+
232+
if inTargetOperation {
233+
currentIndent := len(line) - len(strings.TrimLeft(line, " "))
234+
// If we hit a line at the same or lower indent level, we've left the operation
235+
if strings.TrimSpace(line) != "" && currentIndent <= indentLevel {
236+
break
237+
}
238+
sectionLines = append(sectionLines, line)
239+
}
240+
}
241+
242+
return strings.Join(sectionLines, "\n")
243+
}

0 commit comments

Comments
 (0)