Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,58 @@ package io.github.bgmsound.documentify.core.emitter

import io.github.bgmsound.documentify.core.specification.element.field.Field
import io.github.bgmsound.documentify.core.specification.schema.response.ResponseSpec
import org.hamcrest.Matcher
import org.hamcrest.Matchers

abstract class AbstractDocumentResult : DocumentResult {
abstract fun validateJsonPath(jsonResultMatcher: JsonResultMatcher)
abstract fun expect(jsonPath: String, matcher: Matcher<*>)

abstract fun expectValue(jsonPath: String, value: Any)

override fun validateWith(responseSpec: ResponseSpec) {
val matchers = aggregateMatchers(responseSpec.fields)
if (matchers.isEmpty()) {
return
}
matchers.forEach { matcher ->
validateJsonPath(matcher)
val jsonPath = matcher.jsonPath
val value = matcher.expectedValue
if (jsonPath.endsWith("[*]")) {
if (value !is List<*>) {
throw IllegalArgumentException("sample value type must be List")
Copy link

Copilot AI May 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider enhancing the error message to include the actual type of the received value for easier debugging of type mismatches.

Suggested change
throw IllegalArgumentException("sample value type must be List")
throw IllegalArgumentException("sample value type must be List, but was ${value::class.simpleName}")

Copilot uses AI. Check for mistakes.
}
expect(jsonPath.substringBeforeLast("[*]"), Matchers.containsInAnyOrder(*value.toTypedArray()))
} else if (jsonPath.contains("[*]") && !jsonPath.endsWith("[*]")) {
expect(jsonPath, Matchers.hasItem(value))
} else {
expectValue(jsonPath, value)
}
}
}

private fun aggregateMatchers(fields: List<Field>): List<JsonResultMatcher> {
private fun aggregateMatchers(fields: List<Field>): List<ExpectedJsonValue> {
return fields.filter {
it.hasSample() || it.canHaveChild() || !it.isIgnored()
}.flatMap {
it.aggregateMatchers()
}
}

private fun Field.aggregateMatchers(): List<JsonResultMatcher> {
private fun Field.aggregateMatchers(): List<ExpectedJsonValue> {
if (isIgnored()) {
return emptyList()
}
if (!hasSample() && !canHaveChild()) {
return emptyList()
}
val matchers = mutableListOf<JsonResultMatcher>()
val matchers = mutableListOf<ExpectedJsonValue>()
if (hasSample()) {
val jsonPath = StringBuilder("$.${path}").apply {
if (isArray()) {
append("[*]")
}
}.toString().replace("[]", "[*]")
matchers.add(JsonResultMatcher.of(jsonPath, sample))
matchers.add(ExpectedJsonValue.of(jsonPath, sample))
} else if (childFields().isNotEmpty()) {
val childMatchers = aggregateMatchers(childFields())
matchers.addAll(childMatchers)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package io.github.bgmsound.documentify.core.emitter

data class JsonResultMatcher(
data class ExpectedJsonValue(
val jsonPath: String,
val expectedValue: Any
) {
companion object {
fun of(path: String, expectedValue: Any) = JsonResultMatcher(path, expectedValue)
fun of(path: String, expectedValue: Any) = ExpectedJsonValue(path, expectedValue)
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package io.github.bgmsound.documentify.core.specification
package io.github.bgmsound.documentify.core.specification.schema

import com.epages.restdocs.apispec.ResourceDocumentation
import com.epages.restdocs.apispec.ResourceSnippetParameters
import com.epages.restdocs.apispec.Schema
import io.github.bgmsound.documentify.core.specification.DocumentableSpec
import io.github.bgmsound.documentify.core.specification.element.Link
import io.github.bgmsound.documentify.core.specification.element.field.Field
import io.github.bgmsound.documentify.core.specification.schema.request.RequestSpec
Expand All @@ -28,17 +29,17 @@ class ResourceSpec(
}

fun link(rel: String): Link {
val link = Link.newLink(rel)
val link = Link.Companion.newLink(rel)
this.links.add(link)
return link
}

fun links(vararg links: String) {
this.links.addAll(links.map { Link.newLink(it) })
this.links.addAll(links.map { Link.Companion.newLink(it) })
}

fun links(links: Collection<String>) {
this.links.addAll(links.map { Link.newLink(it) })
this.links.addAll(links.map { Link.Companion.newLink(it) })
}

fun tag(tag: String) {
Expand Down Expand Up @@ -70,7 +71,7 @@ class ResourceSpec(
}

override fun build(): List<Snippet> {
val resourceBuilder = ResourceSnippetParameters.builder()
val resourceBuilder = ResourceSnippetParameters.Companion.builder()
if (tags.isNotEmpty()) {
resourceBuilder.tags(*tags.toTypedArray())
}
Expand All @@ -93,13 +94,13 @@ class ResourceSpec(
}
if (request.fields.isNotEmpty()) {
if (request.schema != null) {
resourceBuilder.requestSchema(Schema.schema(request.schema!!))
resourceBuilder.requestSchema(Schema.Companion.schema(request.schema!!))
}
resourceBuilder.requestFields(buildFields(request.fields))
}
if (response.fields.isNotEmpty()) {
if (response.schema != null) {
resourceBuilder.responseSchema(Schema.schema(response.schema!!))
resourceBuilder.responseSchema(Schema.Companion.schema(response.schema!!))
}
resourceBuilder.responseFields(buildFields(response.fields))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.github.bgmsound.documentify.core.specification.schema.document

import io.github.bgmsound.documentify.core.specification.DocumentableSpec
import io.github.bgmsound.documentify.core.specification.ResourceSpec
import io.github.bgmsound.documentify.core.specification.schema.ResourceSpec
import io.github.bgmsound.documentify.core.specification.schema.Method
import io.github.bgmsound.documentify.core.specification.schema.request.RequestBodySpec
import io.github.bgmsound.documentify.core.specification.schema.request.RequestHeaderSpec
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,20 @@
package io.github.bgmsound.documentify.mvc.emitter

import io.github.bgmsound.documentify.core.emitter.AbstractDocumentResult
import io.github.bgmsound.documentify.core.emitter.JsonResultMatcher
import io.github.bgmsound.documentify.core.specification.schema.response.ResponseSpec
import io.github.bgmsound.documentify.mvc.ValidatableMockResponse
import org.hamcrest.Matchers
import org.hamcrest.Matcher
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath

class MvcDocumentResult(
private val actualResponse: ValidatableMockResponse
) : AbstractDocumentResult() {
override fun validateJsonPath(jsonResultMatcher: JsonResultMatcher) {
val jsonPath = jsonResultMatcher.jsonPath
val value = jsonResultMatcher.expectedValue
override fun expect(jsonPath: String, matcher: Matcher<*>) {
actualResponse.expect(jsonPath(jsonPath).value(matcher))
}

if (jsonPath.endsWith("[*]")) {
if (value !is List<*>) {
throw IllegalArgumentException("sample value type must be List")
}
actualResponse.expect(jsonPath(jsonPath.substringBeforeLast("[*]")).value(Matchers.containsInAnyOrder(*value.toTypedArray())))
} else if (jsonPath.contains("[*]") && !jsonPath.endsWith("[*]")) {
actualResponse.expect(jsonPath(jsonPath).value(Matchers.hasItem(value)))
} else {
actualResponse.expect(jsonPath(jsonPath).value(value))
}
override fun expectValue(jsonPath: String, value: Any) {
actualResponse.expect(jsonPath(jsonPath).value(value))
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,20 @@
package io.github.bgmsound.documentify.reactive.emitter

import io.github.bgmsound.documentify.core.emitter.AbstractDocumentResult
import io.github.bgmsound.documentify.core.emitter.JsonResultMatcher
import io.github.bgmsound.documentify.core.specification.schema.response.ResponseSpec
import org.hamcrest.Matcher
import org.hamcrest.Matchers
import org.springframework.test.web.reactive.server.WebTestClient

class ReactiveDocumentResult(
private val actualResponse: WebTestClient.BodyContentSpec
) : AbstractDocumentResult() {
override fun validateJsonPath(jsonResultMatcher: JsonResultMatcher) {
val jsonPath = jsonResultMatcher.jsonPath
val value = jsonResultMatcher.expectedValue
override fun expect(jsonPath: String, matcher: Matcher<*>) {
actualResponse.jsonPath(jsonPath).value(matcher)
}

if (jsonPath.endsWith("[*]")) {
if (value !is List<*>) {
throw IllegalArgumentException("sample value type must be List")
}
actualResponse.jsonPath(jsonPath.substringBeforeLast("[*]")).value(Matchers.containsInAnyOrder(*value.toTypedArray()))
} else if (jsonPath.contains("[*]") && !jsonPath.endsWith("[*]")) {
actualResponse.jsonPath(jsonPath).value(Matchers.hasItem(value))
} else {
actualResponse.jsonPath(jsonPath).value(Matchers.equalToObject(value))
}
override fun expectValue(jsonPath: String, value: Any) {
actualResponse.jsonPath(jsonPath).value(Matchers.equalToObject(value))
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.bgmsound.documentify.sample.mvc
package io.github.bgmsound.documentify.sample.mvc.controller

import io.github.bgmsound.documentify.sample.mvc.dto.response.ComplexSampleResponse
import io.github.bgmsound.documentify.sample.mvc.dto.response.NestedSampleResponse
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.bgmsound.documentify.sample.mvc
package io.github.bgmsound.documentify.sample.mvc.controller

import io.github.bgmsound.documentify.sample.mvc.dto.response.SampleResponse
import org.springframework.http.ResponseEntity
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.bgmsound.documentify.sample.mvc
package io.github.bgmsound.documentify.sample.mvc.controller

import io.github.bgmsound.documentify.sample.mvc.dto.request.NestedSampleRequest
import io.github.bgmsound.documentify.sample.mvc.dto.response.NestedSampleResponse
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.bgmsound.documentify.sample.mvc
package io.github.bgmsound.documentify.sample.mvc.controller

import io.github.bgmsound.documentify.sample.mvc.dto.request.SampleRequest
import io.github.bgmsound.documentify.sample.mvc.dto.response.SampleResponse
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.bgmsound.documentify.sample.mvc
package io.github.bgmsound.documentify.sample.mvc.controller

import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.bgmsound.documentify.sample.mvc
package io.github.bgmsound.documentify.sample.mvc.controller

import io.github.bgmsound.documentify.sample.mvc.dto.response.SampleResponse
import org.springframework.stereotype.Service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package io.github.bgmsound.documentify.sample.mvc.documentation

import io.github.bgmsound.documentify.core.specification.schema.Method
import io.github.bgmsound.documentify.mvc.Documentify
import io.github.bgmsound.documentify.sample.mvc.ComplexSampleController
import io.github.bgmsound.documentify.sample.mvc.controller.ComplexSampleController
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.restdocs.RestDocumentationContextProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package io.github.bgmsound.documentify.sample.mvc.documentation

import io.github.bgmsound.documentify.core.specification.schema.Method
import io.github.bgmsound.documentify.mvc.Documentify
import io.github.bgmsound.documentify.sample.mvc.ErrorController
import io.github.bgmsound.documentify.sample.mvc.controller.ErrorController
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.restdocs.RestDocumentationContextProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package io.github.bgmsound.documentify.sample.mvc.documentation

import io.github.bgmsound.documentify.core.specification.schema.Method
import io.github.bgmsound.documentify.mvc.Documentify
import io.github.bgmsound.documentify.sample.mvc.NestedSampleController
import io.github.bgmsound.documentify.sample.mvc.controller.NestedSampleController
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.restdocs.RestDocumentationContextProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package io.github.bgmsound.documentify.sample.mvc.documentation

import io.github.bgmsound.documentify.core.specification.schema.Method
import io.github.bgmsound.documentify.mvc.Documentify
import io.github.bgmsound.documentify.sample.mvc.SampleController
import io.github.bgmsound.documentify.sample.mvc.controller.SampleController
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.http.HttpStatus
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies
import com.fasterxml.jackson.module.kotlin.KotlinModule
import io.github.bgmsound.documentify.core.specification.schema.Method
import io.github.bgmsound.documentify.mvc.Documentify
import io.github.bgmsound.documentify.sample.mvc.SampleController
import io.github.bgmsound.documentify.sample.mvc.controller.SampleController
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.http.HttpStatus
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package io.github.bgmsound.documentify.sample.mvc.documentation

import io.github.bgmsound.documentify.core.specification.schema.Method
import io.github.bgmsound.documentify.mvc.Documentify
import io.github.bgmsound.documentify.sample.mvc.UnnestedSampleController
import io.github.bgmsound.documentify.sample.mvc.controller.UnnestedSampleController
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.restdocs.RestDocumentationContextProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package io.github.bgmsound.documentify.sample.mvc.documentation

import io.github.bgmsound.documentify.core.specification.schema.Method
import io.github.bgmsound.documentify.mvc.Documentify
import io.github.bgmsound.documentify.sample.mvc.UseCase
import io.github.bgmsound.documentify.sample.mvc.UseCaseBindingController
import io.github.bgmsound.documentify.sample.mvc.controller.UseCase
import io.github.bgmsound.documentify.sample.mvc.controller.UseCaseBindingController
import io.github.bgmsound.documentify.sample.mvc.dto.response.SampleResponse
import io.mockk.every
import io.mockk.mockk
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
package io.github.bgmsound.documentify.sample.reactive
package io.github.bgmsound.documentify.sample.reactive.controller

import io.github.bgmsound.documentify.sample.reactive.dto.request.SampleRequest
import io.github.bgmsound.documentify.sample.reactive.dto.response.SampleResponse
import kotlinx.coroutines.reactive.awaitFirst
import org.springframework.web.bind.annotation.*
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PatchMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import reactor.core.publisher.Mono

@RestController
Expand All @@ -14,7 +22,6 @@ class SampleController {
@PathVariable("integerField") integerField: Int,
@RequestParam("stringField") stringField: String
): SampleResponse {
"asfd"
return Mono.just(SampleResponse(integerField, stringField)).awaitFirst()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package io.github.bgmsound.documentify.sample.reactive.documentation

import io.github.bgmsound.documentify.core.specification.schema.Method
import io.github.bgmsound.documentify.reactive.Documentify
import io.github.bgmsound.documentify.sample.reactive.SampleController
import io.github.bgmsound.documentify.sample.reactive.controller.SampleController
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies
import com.fasterxml.jackson.module.kotlin.KotlinModule
import io.github.bgmsound.documentify.core.specification.schema.Method
import io.github.bgmsound.documentify.reactive.Documentify
import io.github.bgmsound.documentify.sample.reactive.SampleController
import io.github.bgmsound.documentify.sample.reactive.controller.SampleController
import kotlinx.coroutines.test.runTest

import org.junit.jupiter.api.BeforeEach
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
project.name=documentify

project.group=io.github.bgmsound
project.version.id=1.3.5
project.version.id=1.3.6
project.artifact=documentify

project.description=Documentify is a tool to generate API documentation from source code.
Expand Down
Loading