Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support json and yml extensions #854

Merged
merged 5 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions application/src/main/kotlin/application/CompatibleCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -339,10 +339,10 @@ internal fun generateCommitBackwardCompatibleTests(

internal fun parseContract(content: String, path: String): Feature {
return when(val extension = File(path).extension) {
"yaml" -> OpenApiSpecification.fromYAML(content, path).toFeature()
"wsdl" -> wsdlContentToFeature(content, path)
in OPENAPI_FILE_EXTENSIONS -> OpenApiSpecification.fromYAML(content, path).toFeature()
WSDL -> wsdlContentToFeature(content, path)
in CONTRACT_EXTENSIONS -> parseGherkinStringToFeature(content, path)
else -> throw ContractException("Current file extension is $extension, but supported extensions are ${CONTRACT_EXTENSIONS.joinToString(", ")}")
else -> throw unsupportedFileExtensionContractException(path, extension)
}
}

Expand Down
18 changes: 15 additions & 3 deletions core/src/main/kotlin/in/specmatic/core/Feature.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,25 @@ fun parseContractFileToFeature(file: File, hook: Hook = PassThroughHook(), sourc
logger.debug("Parsing contract file ${file.path}, absolute path ${file.absolutePath}")

return when (file.extension) {
"yaml" -> OpenApiSpecification.fromYAML(hook.readContract(file.path), file.path, sourceProvider =sourceProvider, sourceRepository = sourceRepository, sourceRepositoryBranch = sourceRepositoryBranch, specificationPath = specificationPath, securityConfiguration = securityConfiguration).toFeature()
"wsdl" -> wsdlContentToFeature(checkExists(file).readText(), file.canonicalPath)
in OPENAPI_FILE_EXTENSIONS -> OpenApiSpecification.fromYAML(hook.readContract(file.path), file.path, sourceProvider =sourceProvider, sourceRepository = sourceRepository, sourceRepositoryBranch = sourceRepositoryBranch, specificationPath = specificationPath, securityConfiguration = securityConfiguration).toFeature()
WSDL -> wsdlContentToFeature(checkExists(file).readText(), file.canonicalPath)
in CONTRACT_EXTENSIONS -> parseGherkinStringToFeature(checkExists(file).readText().trim(), file.canonicalPath)
else -> throw ContractException("File extension of ${file.path} not recognized")
else -> throw unsupportedFileExtensionContractException(file.path, file.extension)
}
}

fun unsupportedFileExtensionContractException(
path: String,
extension: String
) =
ContractException(
"Current file $path has an unsupported extension $extension. Supported extensions are ${
CONTRACT_EXTENSIONS.joinToString(
", "
)
}."
)

fun parseGherkinStringToFeature(gherkinData: String, sourceFilePath: String = ""): Feature {
val gherkinDocument = parseGherkinString(gherkinData, sourceFilePath)
val (name, scenarios) = lex(gherkinDocument, sourceFilePath)
Expand Down
7 changes: 6 additions & 1 deletion core/src/main/kotlin/in/specmatic/core/SpecmaticConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ const val APPLICATION_NAME_LOWER_CASE = "specmatic"
const val APPLICATION_NAME_LOWER_CASE_LEGACY = "qontract"
const val CONTRACT_EXTENSION = "spec"
const val LEGACY_CONTRACT_EXTENSION = "qontract"
val CONTRACT_EXTENSIONS = listOf(CONTRACT_EXTENSION, LEGACY_CONTRACT_EXTENSION, "yaml", "wsdl")
const val YAML = "yaml"
const val WSDL = "wsdl"
const val YML = "yml"
const val JSON = "json"
val OPENAPI_FILE_EXTENSIONS = listOf(YAML, YML, JSON)
val CONTRACT_EXTENSIONS = listOf(CONTRACT_EXTENSION, LEGACY_CONTRACT_EXTENSION, WSDL) + OPENAPI_FILE_EXTENSIONS
const val DATA_DIR_SUFFIX = "_data"
const val SPECMATIC_GITHUB_ISSUES = "https://github.com/znsio/specmatic/issues"
const val DEFAULT_WORKING_DIRECTORY = ".$APPLICATION_NAME_LOWER_CASE"
Expand Down
10 changes: 10 additions & 0 deletions core/src/test/kotlin/in/specmatic/core/FeatureKtTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,16 @@ paths:
}
}

@Test
fun `should parse equivalent json and yaml representation of an API`() {
val yamlSpec = parseContractFileToFeature("src/test/resources/openapi/jsonAndYamlEquivalence/openapi.yaml")
val jsonSpec = parseContractFileToFeature("src/test/resources/openapi/jsonAndYamlEquivalence/openapi.json")
val yamlToJson = testBackwardCompatibility(yamlSpec, jsonSpec)
assertThat(yamlToJson.success()).withFailMessage(yamlToJson.report()).isTrue
val jsonToYAml = testBackwardCompatibility(jsonSpec, yamlSpec)
assertThat(jsonToYAml.success()).withFailMessage(jsonToYAml.report()).isTrue
}

fun String.toFeatureString(): String {
val parsedJSONValue = parsedJSON(this) as JSONObjectValue
return toGherkinFeature(NamedStub("Test Feature", mockFromJSON(parsedJSONValue.jsonObject)))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"openapi": "3.0.0",
"info": {
"title": "Text/HTML API",
"version": "1.0.0"
},
"paths": {
"/api": {
"post": {
"summary": "Create a text/html response",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
}
}
}
}
}
},
"responses": {
"200": {
"content": {
"text/html": {
"schema": {
"$ref": "#/components/schemas/Generated"
}
}
},
"description": "Successful response"
}
}
}
}
},
"components": {
"schemas": {
"Generated": {
"type": "string",
"example": "<html><body><h1>Hello, world!</h1></body></html>"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
openapi: 3.0.0
info:
title: Text/HTML API
version: 1.0.0
paths:
/api:
post:
summary: Create a text/html response
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- name
properties:
name:
type: string
responses:
'200':
content:
text/html:
schema:
$ref: '#/components/schemas/Generated'
description: Successful response
components:
schemas:
Generated:
type: string
example: '<html><body><h1>Hello, world!</h1></body></html>'