mod support;
use std::fs;
use support::TestWorkspace;
#[test]
fn import_materializes_schema_based_form_urlencoded_body() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
/pets:
post:
operationId: createPet
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
type: object
required: [name]
properties:
name:
type: string
age:
type: integer
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
assert!(output.stdout.contains("Import complete"), "stdout: {}", output.stdout);
assert!(
output.stdout.contains("Imported: 1 of 1 operation(s)"),
"stdout: {}",
output.stdout
);
assert!(
output.stdout.contains(
"Synthesized a minimal application/x-www-form-urlencoded request body for POST /pets"
),
"stdout: {}",
output.stdout
);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("createPet"), "generated: {}", generated);
assert!(generated.contains("POST [[ BASE_URL ]]/pets"), "generated: {}", generated);
assert!(generated.contains("~ name = example"), "generated: {}", generated);
assert!(!generated.contains("~ age ="), "generated: {}", generated);
}
#[test]
fn import_materializes_example_based_multipart_body() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
/pets:
post:
operationId: createPet
requestBody:
required: true
content:
multipart/form-data:
example:
name: Pickles
age: 3
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
assert!(output.stdout.contains("Import complete"), "stdout: {}", output.stdout);
assert!(
output.stdout.contains("Imported: 1 of 1 operation(s)"),
"stdout: {}",
output.stdout
);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("createPet"), "generated: {}", generated);
assert!(generated.contains("POST [[ BASE_URL ]]/pets"), "generated: {}", generated);
assert!(generated.contains("~ name = Pickles"), "generated: {}", generated);
assert!(generated.contains("~ age = 3"), "generated: {}", generated);
}
#[test]
fn import_materializes_local_multifile_response_schema_ref() {
let workspace = TestWorkspace::new();
workspace.write_file(
"schemas.yaml",
r#"components:
schemas:
Pet:
type: object
required: [id]
properties:
id:
type: string
format: uuid
name:
type: string
"#,
);
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
/pets:
get:
operationId: listPets
responses:
'200':
description: ok
content:
application/json:
schema:
$ref: './schemas.yaml#/components/schemas/Pet'
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
assert!(output.stdout.contains("Import complete"), "stdout: {}", output.stdout);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("listPets"), "generated: {}", generated);
assert!(generated.contains("^ & body === listPetsResponse"), "generated: {}", generated);
assert!(generated.contains("schema listPetsResponse {"), "generated: {}", generated);
assert!(generated.contains("id: UUID"), "generated: {}", generated);
assert!(generated.contains("name?: string"), "generated: {}", generated);
}
#[test]
fn import_materializes_root_component_parameter_request_body_and_response_refs() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
components:
schemas:
Pet:
type: object
required: [id]
properties:
id:
type: string
format: uuid
name:
type: string
parameters:
TraceId:
name: trace-id
in: header
required: true
schema:
type: string
examples:
request:
value: trace-123
requestBodies:
CreatePet:
required: true
content:
application/json:
schema:
type: object
required: [name]
properties:
name:
type: string
responses:
PetCreated:
description: ok
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
paths:
/pets:
post:
operationId: createPet
parameters:
- $ref: '#/components/parameters/TraceId'
requestBody:
$ref: '#/components/requestBodies/CreatePet'
responses:
'201':
$ref: '#/components/responses/PetCreated'
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
assert!(output.stdout.contains("Import complete"), "stdout: {}", output.stdout);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("createPet"), "generated: {}", generated);
assert!(generated.contains("* trace-id = trace-123"), "generated: {}", generated);
assert!(generated.contains("\"name\": \"example\""), "generated: {}", generated);
assert!(generated.contains("^ & body === Pet"), "generated: {}", generated);
}
#[test]
fn import_materializes_root_component_path_item_refs() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
components:
parameters:
TraceId:
name: trace-id
in: header
required: true
schema:
type: string
example: trace-123
pathItems:
Pets:
get:
operationId: listPets
parameters:
- $ref: '#/components/parameters/TraceId'
paths:
/pets:
$ref: '#/components/pathItems/Pets'
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
assert!(output.stdout.contains("Import complete"), "stdout: {}", output.stdout);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("listPets"), "generated: {}", generated);
assert!(generated.contains("GET [[ BASE_URL ]]/pets"), "generated: {}", generated);
assert!(generated.contains("* trace-id = trace-123"), "generated: {}", generated);
}
#[test]
fn import_materializes_json_like_media_types() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
components:
schemas:
Problem:
type: object
required: [detail]
properties:
detail:
type: string
paths:
/pets:
post:
operationId: createPet
requestBody:
required: true
content:
application/merge-patch+json:
schema:
type: object
required: [name]
properties:
name:
type: string
responses:
'200':
description: ok
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
assert!(output.stdout.contains("Import complete"), "stdout: {}", output.stdout);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("createPet"), "generated: {}", generated);
assert!(generated.contains("~~~json"), "generated: {}", generated);
assert!(generated.contains("\"name\": \"example\""), "generated: {}", generated);
assert!(generated.contains("^ & body === Problem"), "generated: {}", generated);
}
#[test]
fn import_materializes_object_allof_schemas() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
components:
schemas:
PetBase:
type: object
required: [id]
properties:
id:
type: string
format: uuid
Pet:
allOf:
- $ref: '#/components/schemas/PetBase'
- type: object
properties:
name:
type: string
paths:
/pets:
post:
operationId: createPet
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/PetBase'
- type: object
required: [name]
properties:
name:
type: string
responses:
'200':
description: ok
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
assert!(output.stdout.contains("Import complete"), "stdout: {}", output.stdout);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("schema Pet {"), "generated: {}", generated);
assert!(generated.contains("id: UUID"), "generated: {}", generated);
assert!(generated.contains("name?: string"), "generated: {}", generated);
assert!(generated.contains("\"id\": \"00000000-0000-0000-0000-000000000000\""), "generated: {}", generated);
assert!(generated.contains("\"name\": \"example\""), "generated: {}", generated);
assert!(generated.contains("^ & body === Pet"), "generated: {}", generated);
}
#[test]
fn import_materializes_oneof_and_discriminator_schemas() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
components:
schemas:
Cat:
type: object
required: [id, lives]
properties:
id:
type: string
format: uuid
lives:
type: integer
Dog:
type: object
required: [id, breed]
properties:
id:
type: string
format: uuid
breed:
type: string
Animal:
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
CardCheckout:
type: object
required: [method, cardLast4]
properties:
method:
type: string
const: card
cardLast4:
type: string
BankCheckout:
type: object
required: [method, accountId]
properties:
method:
type: string
const: bank
accountId:
type: string
Checkout:
oneOf:
- $ref: '#/components/schemas/CardCheckout'
- $ref: '#/components/schemas/BankCheckout'
discriminator:
propertyName: method
mapping:
card: '#/components/schemas/CardCheckout'
bank: '#/components/schemas/BankCheckout'
Result:
oneOf:
- $ref: '#/components/schemas/Animal'
- $ref: '#/components/schemas/Checkout'
paths:
/checkout:
post:
operationId: createCheckout
requestBody:
required: true
content:
application/json:
schema:
discriminator:
propertyName: method
oneOf:
- type: object
required: [method, cardLast4]
properties:
method:
type: string
const: card
cardLast4:
type: string
- type: object
required: [method, accountId]
properties:
method:
type: string
const: bank
accountId:
type: string
responses:
'200':
description: ok
content:
application/json:
schema:
$ref: '#/components/schemas/Result'
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
assert!(output.stdout.contains("Import complete"), "stdout: {}", output.stdout);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("schema Result = oneOf(Animal, Checkout)"), "generated: {}", generated);
assert!(generated.contains("schema Animal = oneOf(Cat, Dog)"), "generated: {}", generated);
assert!(generated.contains("schema Checkout = discriminator(method,"), "generated: {}", generated);
assert!(generated.contains("\"card\":"), "generated: {}", generated);
assert!(generated.contains("\"bank\":"), "generated: {}", generated);
assert!(generated.contains("const(\"card\")"), "generated: {}", generated);
assert!(generated.contains("~~~json"), "generated: {}", generated);
assert!(generated.contains("\"method\": \"card\""), "generated: {}", generated);
assert!(generated.contains("\"cardLast4\": \"example\""), "generated: {}", generated);
assert!(generated.contains("^ & body === Result"), "generated: {}", generated);
}
#[test]
fn import_materializes_plain_component_schema_aliases() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
components:
schemas:
PetBase:
type: object
required: [id]
properties:
id:
type: string
format: uuid
name:
type: string
Pet:
$ref: '#/components/schemas/PetBase'
paths:
/pets:
get:
operationId: getPet
responses:
'200':
description: ok
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
assert!(output.stdout.contains("Import complete"), "stdout: {}", output.stdout);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("schema Pet = PetBase"), "generated: {}", generated);
assert!(generated.contains("schema PetBase {"), "generated: {}", generated);
assert!(generated.contains("id: UUID"), "generated: {}", generated);
assert!(generated.contains("name?: string"), "generated: {}", generated);
assert!(generated.contains("^ & body === Pet"), "generated: {}", generated);
}
#[test]
fn import_materializes_constrained_fields_as_synthetic_scalars() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
components:
schemas:
Pet:
type: object
required: [status, age, tags]
properties:
status:
type: string
enum: [available, pending]
age:
type: integer
minimum: 0
maximum: 20
tags:
type: array
items:
type: string
pattern: '^[a-z]+$'
paths:
/pets:
post:
operationId: createPet
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
responses:
'200':
description: ok
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
assert!(!output.stdout.contains("Omitted scalar constraints"), "stdout: {}", output.stdout);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("scalar Pet_age = integer & range(0..20)"), "generated: {}", generated);
assert!(generated.contains("scalar Pet_status = string & enum(\"available\", \"pending\")"), "generated: {}", generated);
assert!(generated.contains("scalar Pet_tags = string & pattern(/^[a-z]+$/)"), "generated: {}", generated);
assert!(generated.contains("status: Pet_status"), "generated: {}", generated);
assert!(generated.contains("age: Pet_age"), "generated: {}", generated);
assert!(generated.contains("tags: Pet_tags[]"), "generated: {}", generated);
assert!(generated.contains("\"status\": \"available\""), "generated: {}", generated);
assert!(generated.contains("\"age\": 1"), "generated: {}", generated);
assert!(generated.contains("\"tags\": [\n \"example\"\n ]"), "generated: {}", generated);
assert!(generated.contains("^ & body === Pet"), "generated: {}", generated);
}
#[test]
fn import_materializes_openid_connect_as_bearer_placeholder() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
components:
securitySchemes:
oidc:
type: openIdConnect
openIdConnectUrl: https://login.example.com/.well-known/openid-configuration
paths:
/pets:
get:
operationId: listPets
security:
- oidc: []
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
assert!(output.stdout.contains("Import complete"), "stdout: {}", output.stdout);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("listPets"), "generated: {}", generated);
assert!(generated.contains("* Authorization = Bearer [[ oidc_token ]]"), "generated: {}", generated);
}
#[test]
fn import_materializes_oauth_authorization_code_as_bearer_placeholder() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
components:
securitySchemes:
oauthAuthCode:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://login.example.com/oauth/authorize
tokenUrl: https://login.example.com/oauth/token
scopes:
read:pets: Read pets
paths:
/pets:
get:
operationId: listPets
security:
- oauthAuthCode: []
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
assert!(output.stdout.contains("Import complete"), "stdout: {}", output.stdout);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("listPets"), "generated: {}", generated);
assert!(generated.contains("* Authorization = Bearer [[ oauthAuthCode_token ]]"), "generated: {}", generated);
}
#[test]
fn import_materializes_label_style_path_parameter() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
/pets/{petId}:
get:
operationId: getPet
parameters:
- name: petId
in: path
required: true
style: label
schema:
type: string
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("GET [[ BASE_URL ]]/pets/.[[ petId ]]"), "generated: {}", generated);
}
#[test]
fn import_materializes_matrix_style_path_parameter() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
"/pets/{petId}":
get:
operationId: getPet
parameters:
- name: petId
in: path
required: true
style: matrix
schema:
type: string
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("GET [[ BASE_URL ]]/pets/;petId=[[ petId ]]"), "generated: {}", generated);
}
#[test]
fn import_materializes_supported_scalar_parameters() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
"/pets/{petId}":
get:
operationId: getPet
parameters:
- name: petId
in: path
required: true
style: matrix
schema:
type: string
- name: search
in: query
required: true
style: form
schema:
type: string
- name: trace-id
in: header
required: true
style: simple
schema:
type: string
- name: session
in: cookie
required: true
style: form
schema:
type: string
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("GET [[ BASE_URL ]]/pets/;petId=[[ petId ]]"), "generated: {}", generated);
assert!(generated.contains("? search = [[ search ]]"), "generated: {}", generated);
assert!(generated.contains("* trace-id = [[ trace_id ]]"), "generated: {}", generated);
assert!(generated.contains("@ session = [[ session ]]"), "generated: {}", generated);
}
#[test]
fn import_materializes_parameter_examples_and_defaults() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
"/pets/{petId}":
get:
operationId: getPet
parameters:
- name: petId
in: path
required: true
schema:
type: string
example: pet-123
- name: search
in: query
required: true
style: form
schema:
type: string
example: hound
- name: trace-id
in: header
required: true
schema:
type: string
examples:
request:
value: trace-123
- name: session
in: cookie
required: true
schema:
type: string
default: cookie-123
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("GET [[ BASE_URL ]]/pets/pet-123"), "generated: {}", generated);
assert!(generated.contains("? search = hound"), "generated: {}", generated);
assert!(generated.contains("* trace-id = trace-123"), "generated: {}", generated);
assert!(generated.contains("@ session = cookie-123"), "generated: {}", generated);
assert!(!generated.contains("[[ petId ]]"), "generated: {}", generated);
assert!(!generated.contains("[[ search ]]"), "generated: {}", generated);
assert!(!generated.contains("[[ trace_id ]]"), "generated: {}", generated);
assert!(!generated.contains("[[ session ]]"), "generated: {}", generated);
}
#[test]
fn import_materializes_form_exploded_query_array_parameter() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
/pets:
get:
operationId: listPets
parameters:
- name: tag
in: query
required: true
style: form
explode: true
schema:
type: array
items:
type: string
example:
- dog
- cat
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("GET [[ BASE_URL ]]/pets"), "generated: {}", generated);
assert!(generated.contains("? tag = dog"), "generated: {}", generated);
assert!(generated.contains("? tag = cat"), "generated: {}", generated);
}
#[test]
fn import_materializes_concrete_array_parameters_across_supported_locations() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
"/pets/{petId}":
get:
operationId: getPet
parameters:
- name: petId
in: path
required: true
style: matrix
explode: false
schema:
type: array
items:
type: string
example:
- dog
- cat
- name: tag
in: query
required: true
style: form
explode: false
schema:
type: array
items:
type: string
example:
- dog
- cat
- name: x-tag
in: header
required: true
style: simple
explode: false
schema:
type: array
items:
type: string
example:
- dog
- cat
- name: session
in: cookie
required: true
style: form
explode: false
schema:
type: array
items:
type: string
example:
- dog
- cat
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("GET [[ BASE_URL ]]/pets/;petId=dog,cat"), "generated: {}", generated);
assert!(generated.contains("? tag = dog,cat"), "generated: {}", generated);
assert!(generated.contains("* x-tag = dog,cat"), "generated: {}", generated);
assert!(generated.contains("@ session = dog,cat"), "generated: {}", generated);
}
#[test]
fn import_materializes_optional_supported_parameters_with_concrete_values() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
/pets:
get:
operationId: listPets
parameters:
- name: search
in: query
required: false
style: form
schema:
type: string
example: hound
- name: trace-id
in: header
required: false
style: simple
schema:
type: string
examples:
request:
value: trace-123
- name: session
in: cookie
required: false
style: form
schema:
type: string
default: cookie-123
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
assert!(!output.stdout.contains("Omitted optional query parameter"), "stdout: {}", output.stdout);
assert!(!output.stdout.contains("Omitted optional header parameter"), "stdout: {}", output.stdout);
assert!(!output.stdout.contains("Omitted optional cookie parameter"), "stdout: {}", output.stdout);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("? search = hound"), "generated: {}", generated);
assert!(generated.contains("* trace-id = trace-123"), "generated: {}", generated);
assert!(generated.contains("@ session = cookie-123"), "generated: {}", generated);
}
#[test]
fn import_materializes_deep_object_query_parameter() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
/pets:
get:
operationId: listPets
parameters:
- name: filter
in: query
required: true
style: deepObject
explode: true
schema:
type: object
properties:
species:
type: string
age:
type: integer
example:
species: dog
age: 3
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("? filter[age] = 3"), "generated: {}", generated);
assert!(generated.contains("? filter[species] = dog"), "generated: {}", generated);
}
#[test]
fn import_materializes_space_and_pipe_delimited_query_arrays() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
/pets:
get:
operationId: listPets
parameters:
- name: tag
in: query
required: true
style: spaceDelimited
explode: false
schema:
type: array
items:
type: string
example:
- dog
- cat
- name: breed
in: query
required: true
style: pipeDelimited
explode: false
schema:
type: array
items:
type: string
example:
- pug
- beagle
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("? tag = dog cat"), "generated: {}", generated);
assert!(generated.contains("? breed = pug|beagle"), "generated: {}", generated);
}
#[test]
fn import_materializes_form_query_object_parameters() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
/pets:
get:
operationId: listPets
parameters:
- name: filter
in: query
required: true
style: form
explode: true
schema:
type: object
properties:
species:
type: string
age:
type: integer
example:
species: dog
age: 3
- name: filterCompact
in: query
required: true
style: form
explode: false
schema:
type: object
properties:
species:
type: string
age:
type: integer
example:
species: dog
age: 3
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(output.stderr.is_empty(), "stderr: {}", output.stderr);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("? age = 3"), "generated: {}", generated);
assert!(generated.contains("? species = dog"), "generated: {}", generated);
assert!(generated.contains("? filterCompact = age,3,species,dog"), "generated: {}", generated);
}
#[test]
fn import_warns_and_omits_optional_unsupported_parameter() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
/pets:
get:
operationId: listPets
parameters:
- name: filters
in: query
required: false
style: deepObject
explode: true
schema:
type: object
properties:
species:
type: string
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 0, "stderr: {}", output.stderr);
assert!(
output.stdout.contains("Omitted optional query parameter 'filters'"),
"stdout: {}",
output.stdout
);
let generated = fs::read_to_string(workspace.root().join("generated.hen"))
.expect("generated import should be written");
assert!(generated.contains("GET [[ BASE_URL ]]/pets"), "generated: {}", generated);
assert!(!generated.contains("filters"), "generated: {}", generated);
}
#[test]
fn import_fails_when_required_parameter_serialization_is_unsupported() {
let workspace = TestWorkspace::new();
workspace.write_file(
"spec.yaml",
r#"openapi: 3.1.0
paths:
/pets:
get:
operationId: listPets
parameters:
- name: filters
in: query
required: true
style: deepObject
explode: true
schema:
type: object
properties:
species:
type: string
"#,
);
let output = workspace.run_hen(["import", "spec.yaml", "--output", "generated.hen"]);
assert_eq!(output.status_code, 2, "stderr: {}", output.stderr);
assert!(output.stdout.is_empty(), "stdout: {}", output.stdout);
assert!(
output.stderr.contains("no operations could be materialized safely"),
"stderr: {}",
output.stderr
);
assert!(
output.stderr.contains("required query parameter 'filters' uses unsupported OpenAPI serialization"),
"stderr: {}",
output.stderr
);
}