diff --git a/build.gradle b/build.gradle index 7de2046d..04ec06ac 100644 --- a/build.gradle +++ b/build.gradle @@ -73,7 +73,9 @@ subprojects { dependency 'javax.validation:validation-api:1.1.0.Final' dependency 'junit:junit:4.12' dependency 'io.rest-assured:rest-assured:3.0.2' - dependency 'org.asciidoctor:asciidoctorj:1.5.3.1' + dependency 'org.apache.pdfbox:pdfbox:2.0.6' + dependency 'org.asciidoctor:asciidoctorj:1.5.5' + dependency 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.15' dependency 'org.hamcrest:hamcrest-core:1.3' dependency 'org.hamcrest:hamcrest-library:1.3' dependency 'org.hibernate:hibernate-validator:5.4.1.Final' diff --git a/spring-restdocs-asciidoctor/build.gradle b/spring-restdocs-asciidoctor/build.gradle index 0a696d24..51352428 100644 --- a/spring-restdocs-asciidoctor/build.gradle +++ b/spring-restdocs-asciidoctor/build.gradle @@ -3,6 +3,8 @@ description = 'Asciidoctor extensions for Spring REST Docs' dependencies { provided 'org.asciidoctor:asciidoctorj' testCompile 'junit:junit' + testCompile 'org.apache.pdfbox:pdfbox' testCompile 'org.asciidoctor:asciidoctorj' testCompile 'org.springframework:spring-core' + testRuntime 'org.asciidoctor:asciidoctorj-pdf' } \ No newline at end of file diff --git a/spring-restdocs-asciidoctor/src/main/resources/extensions/operation_block_macro.rb b/spring-restdocs-asciidoctor/src/main/resources/extensions/operation_block_macro.rb index 9ddddc2d..5fe2648a 100644 --- a/spring-restdocs-asciidoctor/src/main/resources/extensions/operation_block_macro.rb +++ b/spring-restdocs-asciidoctor/src/main/resources/extensions/operation_block_macro.rb @@ -47,13 +47,15 @@ class OperationBlockMacro < Asciidoctor::Extensions::BlockMacroProcessor def add_blocks(content, doc, parent) options = { safe: doc.options[:safe], - attributes: { 'fragment' => '', - 'projectdir' => doc.attr(:projectdir) } } + attributes: { 'projectdir' => doc.attr(:projectdir) } } fragment = Asciidoctor.load content, options fragment.blocks.each do |b| b.parent = parent parent << b end + parent.find_by.each do |b| + b.parent = b.parent unless b.is_a? Asciidoctor::Document + end end def snippets_to_include(snippet_names, snippets_dir, operation) diff --git a/spring-restdocs-asciidoctor/src/test/java/org/springframework/restdocs/asciidoctor/OperationBlockMacroTests.java b/spring-restdocs-asciidoctor/src/test/java/org/springframework/restdocs/asciidoctor/OperationBlockMacroTests.java index ab0dda63..0770165e 100644 --- a/spring-restdocs-asciidoctor/src/test/java/org/springframework/restdocs/asciidoctor/OperationBlockMacroTests.java +++ b/spring-restdocs-asciidoctor/src/test/java/org/springframework/restdocs/asciidoctor/OperationBlockMacroTests.java @@ -22,7 +22,14 @@ import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import org.apache.pdfbox.contentstream.PDFStreamEngine; +import org.apache.pdfbox.contentstream.operator.Operator; +import org.apache.pdfbox.cos.COSBase; +import org.apache.pdfbox.cos.COSString; +import org.apache.pdfbox.pdmodel.PDDocument; import org.asciidoctor.Asciidoctor; import org.asciidoctor.Attributes; import org.asciidoctor.Options; @@ -33,6 +40,7 @@ import org.junit.Test; import org.springframework.util.FileSystemUtils; import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.hasItems; import static org.hamcrest.CoreMatchers.startsWith; import static org.junit.Assert.assertThat; @@ -62,12 +70,38 @@ public class OperationBlockMacroTests { } @Test - public void simpleSnippetInclude() throws Exception { + public void codeBlockSnippetInclude() throws Exception { String result = this.asciidoctor.convert( "operation::some-operation[snippets='curl-request']", this.options); assertThat(result, equalTo(getExpectedContentFromFile("snippet-simple"))); } + @Test + public void codeBlockSnippetIncludeWithPdfBackend() throws Exception { + File output = configurePdfOutput(); + this.asciidoctor.convert("operation::some-operation[snippets='curl-request']", + this.options); + assertThat(extractStrings(output), + hasItems("Curl request", "$ curl 'http://localhost:8080/' -i", "1")); + } + + @Test + public void tableSnippetInclude() throws Exception { + String result = this.asciidoctor.convert( + "operation::some-operation[snippets='response-fields']", this.options); + assertThat(result, equalTo(getExpectedContentFromFile("snippet-table"))); + } + + @Test + public void tableSnippetIncludeWithPdfBackend() throws Exception { + File output = configurePdfOutput(); + this.asciidoctor.convert("operation::some-operation[snippets='response-fields']", + this.options); + assertThat(extractStrings(output), + hasItems("Response fields", "Path", "Type", "Description", "a", "Object", + "one", "a.b", "Number", "two", "a.c", "String", "three", "1")); + } + @Test public void includeSnippetInSection() throws Exception { String result = this.asciidoctor.convert( @@ -76,6 +110,16 @@ public class OperationBlockMacroTests { assertThat(result, equalTo(getExpectedContentFromFile("snippet-in-section"))); } + @Test + public void includeSnippetInSectionWithPdfBackend() throws Exception { + File output = configurePdfOutput(); + this.asciidoctor.convert( + "== Section\n" + "operation::some-operation[snippets='curl-request']", + this.options); + assertThat(extractStrings(output), hasItems("Section", "Curl request", + "$ curl 'http://localhost:8080/' -i", "1")); + } + @Test public void includeMultipleSnippets() throws Exception { String result = this.asciidoctor.convert( @@ -163,4 +207,41 @@ public class OperationBlockMacroTests { return attributes; } + private File configurePdfOutput() { + this.options.setBackend("pdf"); + File output = new File("build/output.pdf"); + this.options.setToFile(output.getAbsolutePath()); + return output; + } + + private List extractStrings(File pdfFile) throws IOException { + PDDocument pdf = PDDocument.load(pdfFile); + assertThat(pdf.getNumberOfPages(), equalTo(1)); + StringExtractor stringExtractor = new StringExtractor(); + stringExtractor.processPage(pdf.getPage(0)); + return stringExtractor.getStrings(); + } + + private static final class StringExtractor extends PDFStreamEngine { + + private final List strings = new ArrayList<>(); + + @Override + protected void processOperator(Operator operator, List operands) + throws IOException { + if ("Tj".equals(operator.getName())) { + for (COSBase operand : operands) { + if (operand instanceof COSString) { + this.strings.add((((COSString) operand).getASCII())); + } + } + } + } + + public List getStrings() { + return this.strings; + } + + } + } diff --git a/spring-restdocs-asciidoctor/src/test/resources/operations/all-snippets.html b/spring-restdocs-asciidoctor/src/test/resources/operations/all-snippets.html index 9cb2f024..524e1ee7 100644 --- a/spring-restdocs-asciidoctor/src/test/resources/operations/all-snippets.html +++ b/spring-restdocs-asciidoctor/src/test/resources/operations/all-snippets.html @@ -28,4 +28,40 @@ Host: localhost:8080 + +
+

Response fields

+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + +
PathTypeDescription

a

Object

one

a.b

Number

two

a.c

String

three

+
\ No newline at end of file diff --git a/spring-restdocs-asciidoctor/src/test/resources/operations/snippet-table.html b/spring-restdocs-asciidoctor/src/test/resources/operations/snippet-table.html new file mode 100644 index 00000000..a8241a03 --- /dev/null +++ b/spring-restdocs-asciidoctor/src/test/resources/operations/snippet-table.html @@ -0,0 +1,36 @@ +
+

Response fields

+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + +
PathTypeDescription

a

Object

one

a.b

Number

two

a.c

String

three

+
+
\ No newline at end of file diff --git a/spring-restdocs-asciidoctor/src/test/resources/some-operation/response-fields.adoc b/spring-restdocs-asciidoctor/src/test/resources/some-operation/response-fields.adoc new file mode 100644 index 00000000..9c0dcd21 --- /dev/null +++ b/spring-restdocs-asciidoctor/src/test/resources/some-operation/response-fields.adoc @@ -0,0 +1,16 @@ +|=== +|Path|Type|Description + +|`a` +|`Object` +|one + +|`a.b` +|`Number` +|two + +|`a.c` +|`String` +|three + +|=== \ No newline at end of file