/** * Returns a new {@code Snippet} that will document the links in the API operation's * response. Links will be extracted from the response using the given * {@code linkExtractor} and will be documented using the given {@code descriptors}. * <p> * If a link is documented, is not marked as optional, and is not present in the * response, a failure will occur. Any undocumented links will be ignored. * <p> * If a descriptor does not have a {@link LinkDescriptor#description(Object) * description}, the {@link Link#getTitle() title} of the link will be used. If the * link does not have a title a failure will occur. * @param linkExtractor used to extract the links from the response * @param descriptors the descriptions of the response's links * @return the snippet that will document the links */ public static LinksSnippet relaxedLinks(LinkExtractor linkExtractor, List<LinkDescriptor> descriptors) { return new LinksSnippet(linkExtractor, descriptors, true); }
/** * Returns a new {@code Snippet} that will document the links in the API operation's * response. The given {@code attributes} will be available during snippet generation. * Links will be extracted from the response using the given {@code linkExtractor} and * will be documented using the given {@code descriptors}. * <p> * If a link is documented, is not marked as optional, and is not present in the * response, a failure will occur. Any undocumented links will be ignored. * <p> * If a descriptor does not have a {@link LinkDescriptor#description(Object) * description}, the {@link Link#getTitle() title} of the link will be used. If the * link does not have a title a failure will occur. * @param attributes the attributes * @param linkExtractor used to extract the links from the response * @param descriptors the descriptions of the response's links * @return the snippet that will document the links */ public static LinksSnippet relaxedLinks(LinkExtractor linkExtractor, Map<String, Object> attributes, List<LinkDescriptor> descriptors) { return new LinksSnippet(linkExtractor, descriptors, attributes, true); }
/** * Returns a new {@code LinksSnippet} configured with this snippet's link extractor * and attributes, and its descriptors combined with the given * {@code additionalDescriptors}. * @param additionalDescriptors the additional descriptors * @return the new snippet */ public final LinksSnippet and(List<LinkDescriptor> additionalDescriptors) { List<LinkDescriptor> combinedDescriptors = new ArrayList<>( this.descriptorsByRel.values()); combinedDescriptors.addAll(additionalDescriptors); return new LinksSnippet(this.linkExtractor, combinedDescriptors, getAttributes()); }
/** * Returns a new {@code Snippet} that will document the links in the API operation's * response. Links will be extracted from the response automatically based on its * content type and will be documented using the given {@code descriptors}. * <p> * If a link is documented, is not marked as optional, and is not present in the * response, a failure will occur. Any undocumented links will be ignored. * <p> * If a descriptor does not have a {@link LinkDescriptor#description(Object) * description}, the {@link Link#getTitle() title} of the link will be used. If the * link does not have a title a failure will occur. * @param descriptors the descriptions of the response's links * @return the snippet that will document the links */ public static LinksSnippet relaxedLinks(List<LinkDescriptor> descriptors) { return new LinksSnippet(new ContentTypeLinkExtractor(), descriptors, true); }
/** * Returns a new {@code Snippet} that will document the links in the API call's * response. The given {@code attributes} will be available during snippet generation. * Links will be extracted from the response automatically based on its content type * and will be documented using the given {@code descriptors}. * <p> * If a link is documented, is not marked as optional, and is not present in the * response, a failure will occur. Any undocumented links will be ignored. * <p> * If a descriptor does not have a {@link LinkDescriptor#description(Object) * description}, the {@link Link#getTitle() title} of the link will be used. If the * link does not have a title a failure will occur. * @param attributes the attributes * @param descriptors the descriptions of the response's links * @return the snippet that will document the links */ public static LinksSnippet relaxedLinks(Map<String, Object> attributes, List<LinkDescriptor> descriptors) { return new LinksSnippet(new ContentTypeLinkExtractor(), descriptors, attributes, true); }
/** * Returns a new {@code Snippet} that will document the links in the API operation's * response. Links will be extracted from the response automatically based on its * content type and will be documented using the given {@code descriptors}. * <p> * If a link is present in the response, but is not documented by one of the * descriptors, a failure will occur when the snippet is invoked. Similarly, if a link * is documented, is not marked as optional, and is not present in the response, a * failure will also occur. * <p> * If you do not want to document a link, a link descriptor can be marked as * {@link LinkDescriptor#ignored}. This will prevent it from appearing in the * generated snippet while avoiding the failure described above. * <p> * If a descriptor does not have a {@link LinkDescriptor#description(Object) * description}, the {@link Link#getTitle() title} of the link will be used. If the * link does not have a title a failure will occur. * @param descriptors the descriptions of the response's links * @return the snippet that will document the links */ public static LinksSnippet links(List<LinkDescriptor> descriptors) { return new LinksSnippet(new ContentTypeLinkExtractor(), descriptors); }
/** * Returns a new {@code Snippet} that will document the links in the API call's * response. The given {@code attributes} will be available during snippet generation. * Links will be extracted from the response automatically based on its content type * and will be documented using the given {@code descriptors}. * <p> * If a link is present in the response, but is not documented by one of the * descriptors, a failure will occur when the snippet is invoked. Similarly, if a link * is documented, is not marked as optional, and is not present in the response, a * failure will also occur. * <p> * If you do not want to document a link, a link descriptor can be marked as * {@link LinkDescriptor#ignored}. This will prevent it from appearing in the * generated snippet while avoiding the failure described above. * <p> * If a descriptor does not have a {@link LinkDescriptor#description(Object) * description}, the {@link Link#getTitle() title} of the link will be used. If the * link does not have a title a failure will occur. * @param attributes the attributes * @param descriptors the descriptions of the response's links * @return the snippet that will document the links */ public static LinksSnippet links(Map<String, Object> attributes, List<LinkDescriptor> descriptors) { return new LinksSnippet(new ContentTypeLinkExtractor(), descriptors, attributes); }
@Test public void undocumentedLink() throws IOException { this.thrown.expect(SnippetException.class); this.thrown.expectMessage(equalTo( "Links with the following relations were not" + " documented: [foo]")); new LinksSnippet(new StubLinkExtractor().withLinks(new Link("foo", "bar")), Collections.<LinkDescriptor>emptyList()) .document(this.operationBuilder.build()); }
@Test public void missingLink() throws IOException { this.thrown.expect(SnippetException.class); this.thrown.expectMessage(equalTo("Links with the following relations were not" + " found in the response: [foo]")); new LinksSnippet(new StubLinkExtractor(), Arrays.asList(new LinkDescriptor("foo").description("bar"))) .document(this.operationBuilder.build()); }
@Test public void linkWithNoDescription() throws IOException { this.thrown.expect(SnippetException.class); this.thrown.expectMessage( equalTo("No description was provided for the link with rel 'foo' and no" + " title was available from the link in the payload")); new LinksSnippet(new StubLinkExtractor().withLinks(new Link("foo", "bar")), Arrays.asList(new LinkDescriptor("foo"))) .document(this.operationBuilder.build()); }
@Test public void undocumentedLinkAndMissingLink() throws IOException { this.thrown.expect(SnippetException.class); this.thrown.expectMessage(equalTo("Links with the following relations were not" + " documented: [a]. Links with the following relations were not" + " found in the response: [foo]")); new LinksSnippet(new StubLinkExtractor().withLinks(new Link("a", "alpha")), Arrays.asList(new LinkDescriptor("foo").description("bar"))) .document(this.operationBuilder.build()); }
@Test public void missingOptionalLink() throws IOException { new LinksSnippet(new StubLinkExtractor(), Arrays.asList(new LinkDescriptor("foo").description("bar").optional())) .document(this.operationBuilder.build()); assertThat(this.generatedSnippets.links()) .is(tableWithHeader("Relation", "Description").row("`foo`", "bar")); }
@Test public void presentOptionalLink() throws IOException { new LinksSnippet(new StubLinkExtractor().withLinks(new Link("foo", "blah")), Arrays.asList(new LinkDescriptor("foo").description("bar").optional())) .document(this.operationBuilder.build()); assertThat(this.generatedSnippets.links()) .is(tableWithHeader("Relation", "Description").row("`foo`", "bar")); }
@Test public void tableCellContentIsEscapedWhenNecessary() throws IOException { new LinksSnippet(new StubLinkExtractor().withLinks(new Link("Foo|Bar", "foo")), Arrays.asList(new LinkDescriptor("Foo|Bar").description("one|two"))) .document(this.operationBuilder.build()); assertThat(this.generatedSnippets.links()) .is(tableWithHeader("Relation", "Description").row( escapeIfNecessary("`Foo|Bar`"), escapeIfNecessary("one|two"))); }
@Test public void allUndocumentedLinksCanBeIgnored() throws IOException { new LinksSnippet( new StubLinkExtractor().withLinks(new Link("a", "alpha"), new Link("b", "bravo")), Arrays.asList(new LinkDescriptor("b").description("Link b")), true) .document(this.operationBuilder.build()); assertThat(this.generatedSnippets.links()) .is(tableWithHeader("Relation", "Description").row("`b`", "Link b")); }
@Test public void linksWithCustomAttributes() throws IOException { TemplateResourceResolver resolver = mock(TemplateResourceResolver.class); given(resolver.resolveTemplateResource("links")) .willReturn(snippetResource("links-with-title")); new LinksSnippet( new StubLinkExtractor().withLinks(new Link("a", "alpha"), new Link("b", "bravo")), Arrays.asList(new LinkDescriptor("a").description("one"), new LinkDescriptor("b").description("two")), attributes(key("title").value("Title for the links"))) .document( this.operationBuilder .attribute(TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)) .build()); assertThat(this.generatedSnippets.links()).contains("Title for the links"); }
@Test public void ignoredLink() throws IOException { new LinksSnippet( new StubLinkExtractor().withLinks(new Link("a", "alpha"), new Link("b", "bravo")), Arrays.asList(new LinkDescriptor("a").ignored(), new LinkDescriptor("b").description("Link b"))) .document(this.operationBuilder.build()); assertThat(this.generatedSnippets.links()) .is(tableWithHeader("Relation", "Description").row("`b`", "Link b")); }
@Test public void linkDescriptionFromTitleInPayload() throws IOException { new LinksSnippet( new StubLinkExtractor().withLinks(new Link("a", "alpha", "Link a"), new Link("b", "bravo", "Link b")), Arrays.asList(new LinkDescriptor("a").description("one"), new LinkDescriptor("b"))).document(this.operationBuilder.build()); assertThat(this.generatedSnippets.links()) .is(tableWithHeader("Relation", "Description").row("`a`", "one") .row("`b`", "Link b")); }
@Test public void documentedLinks() throws IOException { new LinksSnippet( new StubLinkExtractor().withLinks(new Link("a", "alpha"), new Link("b", "bravo")), Arrays.asList(new LinkDescriptor("a").description("one"), new LinkDescriptor("b").description("two"))) .document(this.operationBuilder.build()); assertThat(this.generatedSnippets.links()) .is(tableWithHeader("Relation", "Description").row("`a`", "one") .row("`b`", "two")); }
@Test public void linksWithCustomDescriptorAttributes() throws IOException { TemplateResourceResolver resolver = mock(TemplateResourceResolver.class); given(resolver.resolveTemplateResource("links")) .willReturn(snippetResource("links-with-extra-column")); new LinksSnippet( new StubLinkExtractor().withLinks(new Link("a", "alpha"), new Link("b", "bravo")), Arrays.asList( new LinkDescriptor("a").description("one") .attributes(key("foo").value("alpha")), new LinkDescriptor("b").description("two") .attributes(key("foo").value("bravo")))) .document(this.operationBuilder.attribute( TemplateEngine.class.getName(), new MustacheTemplateEngine(resolver)) .build()); assertThat(this.generatedSnippets.links()) .is(tableWithHeader("Relation", "Description", "Foo") .row("a", "one", "alpha").row("b", "two", "bravo")); }