From commits-return-5344-archive-asf-public=cust-asf.ponee.io@juneau.apache.org Sun Jul 1 21:22:00 2018 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id 0363F180654 for ; Sun, 1 Jul 2018 21:21:54 +0200 (CEST) Received: (qmail 504 invoked by uid 500); 1 Jul 2018 19:21:54 -0000 Mailing-List: contact commits-help@juneau.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@juneau.apache.org Delivered-To: mailing list commits@juneau.apache.org Received: (qmail 495 invoked by uid 99); 1 Jul 2018 19:21:53 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 01 Jul 2018 19:21:53 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id C317B8080F; Sun, 1 Jul 2018 19:21:52 +0000 (UTC) Date: Sun, 01 Jul 2018 19:21:52 +0000 To: "commits@juneau.apache.org" Subject: [juneau] branch master updated: Combine remoteable and servlet annotations. MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Message-ID: <153047291259.15307.5099504134277371743@gitbox.apache.org> From: jamesbognar@apache.org X-Git-Host: gitbox.apache.org X-Git-Repo: juneau X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: 854d4c13c23011a3333dae35c762d0051a2e0237 X-Git-Newrev: 2d39a182592296b7e08dc8e8d5d1689ebfe28875 X-Git-Rev: 2d39a182592296b7e08dc8e8d5d1689ebfe28875 X-Git-NotificationType: ref_changed_plus_diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated This is an automated email from the ASF dual-hosted git repository. jamesbognar pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/juneau.git The following commit(s) were added to refs/heads/master by this push: new 2d39a18 Combine remoteable and servlet annotations. 2d39a18 is described below commit 2d39a182592296b7e08dc8e8d5d1689ebfe28875 Author: JamesBognar AuthorDate: Sun Jul 1 15:21:25 2018 -0400 Combine remoteable and servlet annotations. --- .../juneau/httppart/HttpPartSchemaTest_Body.java | 1310 ++++++++++++++++++ .../httppart/HttpPartSchemaTest_FormData.java | 1419 ++++++++++++++++++++ .../juneau/httppart/HttpPartSchemaTest_Header.java | 1389 +++++++++++++++++++ .../juneau/httppart/HttpPartSchemaTest_Path.java | 1332 ++++++++++++++++++ .../juneau/httppart/HttpPartSchemaTest_Query.java | 1419 ++++++++++++++++++++ .../org/apache/juneau/testutils/TestUtils.java | 2 + .../juneau/http/annotation}/AnnotationUtils.java | 452 ++++--- .../org/apache/juneau/http}/annotation/Body.java | 97 +- .../apache/juneau/http}/annotation/Contact.java | 2 +- .../juneau/http}/annotation/ExternalDocs.java | 2 +- .../apache/juneau/http}/annotation/FormData.java | 261 +++- .../juneau/http}/annotation/HasFormData.java | 8 +- .../apache/juneau/http}/annotation/HasQuery.java | 6 +- .../org/apache/juneau/http}/annotation/Header.java | 253 +++- .../org/apache/juneau/http}/annotation/Items.java | 2 +- .../apache/juneau/http}/annotation/License.java | 2 +- .../org/apache/juneau/http}/annotation/Path.java | 218 ++- .../juneau/http}/annotation/PathRemainder.java | 4 +- .../org/apache/juneau/http}/annotation/Query.java | 257 +++- .../apache/juneau/http}/annotation/Response.java | 18 +- .../juneau/http}/annotation/ResponseHeader.java | 31 +- .../juneau/http}/annotation/ResponseStatus.java | 4 +- .../juneau/http}/annotation/ResponseStatuses.java | 2 +- .../apache/juneau/http}/annotation/Responses.java | 2 +- .../org/apache/juneau/http}/annotation/Schema.java | 9 +- .../apache/juneau/http}/annotation/SubItems.java | 2 +- .../org/apache/juneau/http}/annotation/Tag.java | 2 +- .../org/apache/juneau/httppart/HttpPartParser.java | 5 +- .../org/apache/juneau/httppart/HttpPartSchema.java | 998 ++++++++++++-- .../apache/juneau/httppart/HttpPartSerializer.java | 9 +- .../httppart/SchemaValidationParseException.java | 22 +- .../SchemaValidationSerializeException.java | 22 +- .../apache/juneau/httppart/SimplePartParser.java | 3 +- .../juneau/httppart/oapi/OapiPartParser.java | 12 +- .../apache/juneau/httppart/uon/UonPartParser.java | 7 +- .../apache/juneau/internal/ReflectionUtils.java | 32 + .../java/org/apache/juneau/remoteable/Body.java | 80 -- .../org/apache/juneau/remoteable/FormData.java | 220 --- .../org/apache/juneau/remoteable/FormDataIfNE.java | 62 - .../java/org/apache/juneau/remoteable/Header.java | 205 --- .../org/apache/juneau/remoteable/HeaderIfNE.java | 62 - .../java/org/apache/juneau/remoteable/Path.java | 192 --- .../java/org/apache/juneau/remoteable/Query.java | 219 --- .../org/apache/juneau/remoteable/QueryIfNE.java | 62 - .../juneau/remoteable/RemoteableMethodMeta.java | 11 +- .../juneau/serializer/SerializeException.java | 2 +- juneau-doc/src/main/javadoc/overview.html | 12 +- .../juneau/examples/rest/AtomFeedResource.java | 1 + .../examples/rest/CodeFormatterResource.java | 1 + .../examples/rest/DockerRegistryResource.java | 1 + .../juneau/examples/rest/JsonSchemaResource.java | 1 + .../examples/rest/MethodExampleResource.java | 1 + .../juneau/examples/rest/PhotosResource.java | 1 + .../examples/rest/PredefinedLabelsResource.java | 1 + .../juneau/examples/rest/RequestEchoResource.java | 1 + .../examples/rest/SampleRemoteableServlet.java | 1 + .../juneau/examples/rest/SqlQueryResource.java | 3 +- .../examples/rest/SystemPropertiesResource.java | 3 +- .../juneau/examples/rest/TempDirResource.java | 1 + .../examples/rest/UrlEncodedFormResource.java | 3 +- .../rest/addressbook/AddressBookResource.java | 1 + .../juneau/examples/rest/petstore/IdConflict.java | 2 +- .../juneau/examples/rest/petstore/IdNotFound.java | 2 +- .../juneau/examples/rest/petstore/InvalidId.java | 2 +- .../examples/rest/petstore/InvalidLogin.java | 2 +- .../examples/rest/petstore/InvalidSpecies.java | 2 +- .../juneau/examples/rest/petstore/InvalidTag.java | 2 +- .../examples/rest/petstore/InvalidUsername.java | 2 +- .../examples/rest/petstore/PetStoreResource.java | 10 +- .../microservice/resources/ConfigResource.java | 3 +- .../microservice/resources/DirectoryResource.java | 1 + .../microservice/resources/LogsResource.java | 1 + .../apache/juneau/rest/test/ConfigResource.java | 1 + .../juneau/rest/test/LargePojosResource.java | 1 + .../rest/test/client/ThirdPartyProxyResource.java | 36 +- .../org/apache/juneau/rest/test/MockRestTest.java | 1 + .../rest/test/client/RequestBeanProxyTest.java | 1028 ++------------ .../rest/test/client/ThirdPartyProxyTest.java | 1090 +-------------- .../org/apache/juneau/rest/client/RestCall.java | 25 +- .../juneau/rest/client/RestCallException.java | 45 +- .../org/apache/juneau/rest/client/RestClient.java | 17 +- .../rest/client/SerializedNameValuePair.java | 7 +- .../apache/juneau/rest/BasicRestCallHandler.java | 10 +- .../apache/juneau/rest/BasicRestInfoProvider.java | 35 +- .../java/org/apache/juneau/rest/RequestBody.java | 172 +-- .../org/apache/juneau/rest/RequestFormData.java | 110 +- .../org/apache/juneau/rest/RequestHeaders.java | 47 +- .../org/apache/juneau/rest/RequestPathMatch.java | 52 +- .../java/org/apache/juneau/rest/RequestQuery.java | 101 +- .../java/org/apache/juneau/rest/RestContext.java | 129 +- .../org/apache/juneau/rest/RestJavaMethod.java | 1 + .../org/apache/juneau/rest/RestMethodParam.java | 20 +- .../org/apache/juneau/rest/RestMethodReturn.java | 28 +- .../org/apache/juneau/rest/RestMethodThrown.java | 27 +- .../org/apache/juneau/rest/RestParamDefaults.java | 306 ++--- .../java/org/apache/juneau/rest/RestRequest.java | 3 +- .../juneau/rest/annotation/MethodSwagger.java | 1 + .../juneau/rest/annotation/ResourceSwagger.java | 1 + .../apache/juneau/rest/annotation/RestMethod.java | 1 + .../apache/juneau/rest/exception/BadRequest.java | 2 +- .../org/apache/juneau/rest/exception/Conflict.java | 2 +- .../juneau/rest/exception/ExpectationFailed.java | 2 +- .../juneau/rest/exception/FailedDependency.java | 2 +- .../apache/juneau/rest/exception/Forbidden.java | 2 +- .../org/apache/juneau/rest/exception/Gone.java | 2 +- .../rest/exception/HttpVersionNotSupported.java | 2 +- .../juneau/rest/exception/InsufficientStorage.java | 2 +- .../juneau/rest/exception/InternalServerError.java | 2 +- .../juneau/rest/exception/LengthRequired.java | 2 +- .../org/apache/juneau/rest/exception/Locked.java | 2 +- .../apache/juneau/rest/exception/LoopDetected.java | 2 +- .../juneau/rest/exception/MethodNotAllowed.java | 2 +- .../juneau/rest/exception/MisdirectedRequest.java | 2 +- .../exception/NetworkAuthenticationRequired.java | 2 +- .../juneau/rest/exception/NotAcceptable.java | 2 +- .../apache/juneau/rest/exception/NotExtended.java | 2 +- .../org/apache/juneau/rest/exception/NotFound.java | 2 +- .../juneau/rest/exception/NotImplemented.java | 2 +- .../juneau/rest/exception/PayloadTooLarge.java | 2 +- .../juneau/rest/exception/PreconditionFailed.java | 2 +- .../rest/exception/PreconditionRequired.java | 2 +- .../juneau/rest/exception/RangeNotSatisfiable.java | 2 +- .../exception/RequestHeaderFieldsTooLarge.java | 2 +- .../juneau/rest/exception/ServiceUnavailable.java | 2 +- .../juneau/rest/exception/TooManyRequests.java | 2 +- .../apache/juneau/rest/exception/Unauthorized.java | 2 +- .../rest/exception/UnavailableForLegalReasons.java | 2 +- .../juneau/rest/exception/UnprocessableEntity.java | 2 +- .../rest/exception/UnsupportedMediaType.java | 2 +- .../juneau/rest/exception/UpgradeRequired.java | 2 +- .../apache/juneau/rest/exception/UriTooLong.java | 2 +- .../rest/exception/VariantAlsoNegotiates.java | 2 +- .../java/org/apache/juneau/rest/helper/Ok.java | 2 +- .../org/apache/juneau/rest/helper/Redirect.java | 2 +- .../juneau/rest/helper/RedirectToServletRoot.java | 2 +- .../juneau/rest/helper/ResourceDescription.java | 2 +- .../juneau/rest/remoteable/RemoteableServlet.java | 3 +- .../apache/juneau/rest/util/AnnotationUtils.java | 655 +-------- .../juneau/rest/BasicRestInfoProviderTest.java | 7 +- .../juneau/rest/BeanContextPropertiesTest.java | 1 + .../java/org/apache/juneau/rest/PathsTest.java | 1 + .../org/apache/juneau/rest/StatusCodesTest.java | 7 +- .../juneau/rest/annotation/BodyAnnotationTest.java | 1 + .../rest/annotation/FormDataAnnotationTest.java | 3 +- .../rest/annotation/HasFormDataAnnotationTest.java | 1 + .../rest/annotation/HasQueryAnnotationTest.java | 1 + .../rest/annotation/HeaderAnnotationTest.java | 1 + .../juneau/rest/annotation/PathAnnotationTest.java | 1 + .../annotation/PathRemainderAnnotationTest.java | 1 + .../rest/annotation/QueryAnnotationTest.java | 6 +- .../rest/annotation/ResponseAnnotationTest.java | 105 +- .../annotation/ResponseHeaderAnnotationTest.java | 356 +---- .../annotation/ResponseStatusAnnotationTest.java | 1 + .../rest/annotation/ResponsesAnnotationTest.java | 47 +- .../juneau/rest/annotation/RestHookTest.java | 1 + .../rest/annotation/RestMethodInheritTest.java | 1 + .../rest/annotation/RestResourceParsersTest.java | 1 + .../rest/annotation/RestResourcePojoSwapsTest.java | 1 + .../juneau/rest/headers/AcceptCharsetTest.java | 1 + .../org/apache/juneau/rest/headers/AcceptTest.java | 1 + .../juneau/rest/headers/ContentEncodingTest.java | 1 + .../juneau/rest/headers/ContentTypeTest.java | 1 + .../apache/juneau/rest/headers/HeadersTest.java | 1 + 163 files changed, 10076 insertions(+), 5291 deletions(-) diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Body.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Body.java new file mode 100644 index 0000000..e83fd32 --- /dev/null +++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Body.java @@ -0,0 +1,1310 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.httppart; + +import static org.junit.Assert.*; + +import static org.apache.juneau.testutils.TestUtils.*; +import static org.apache.juneau.internal.StringUtils.*; + +import org.apache.juneau.*; +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.utils.*; +import org.junit.*; + +public class HttpPartSchemaTest_Body { + + //----------------------------------------------------------------------------------------------------------------- + // Basic test + //----------------------------------------------------------------------------------------------------------------- + @Test + public void testBasic() throws Exception { + HttpPartSchema.create().build(); + } + + //----------------------------------------------------------------------------------------------------------------- + // @Body + //----------------------------------------------------------------------------------------------------------------- + + @Body( + required=true, + description={"b1","b2"}, + schema=@Schema($ref="c1"), + example="f1", + api="{g1:true}" + ) + public static class A02 {} + + @Test + public void a02_basic_onClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, A02.class).noValidate(true).build(); + assertTrue(s.getRequired()); + assertObjectEquals("{description:'b1\\nb2',example:'f1',required:true,schema:{'$ref':'c1'},_value:'{g1:true}'}", s.getApi()); + } + + public static class A03 { + public void a( + @Body( + required=true, + description={"b1","b2"}, + schema=@Schema($ref="c1"), + example="f1", + api="{g1:true}" + ) String x + ) { + + } + } + + @Test + public void a03_basic_onParameter() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, A03.class.getMethod("a", String.class), 0).noValidate(true).build(); + assertTrue(s.getRequired()); + assertObjectEquals("{description:'b1\\nb2',example:'f1',required:true,schema:{'$ref':'c1'},_value:'{g1:true}'}", s.getApi()); + } + + public static class A04 { + public void a( + @Body( + required=false, + description={"b3","b3"}, + schema=@Schema($ref="c3"), + example="f2", + api="{g2:true}" + ) A02 x + ) { + + } + } + + @Test + public void a04_basic_onParameterAndClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, A04.class.getMethod("a", A02.class), 0).noValidate(true).build(); + assertNull(s.getRequired()); + assertObjectEquals("{description:'b3\\nb3',example:'f2',schema:{'$ref':'c3'},_value:'{g2:true}'}", s.getApi()); + } + + @Body( + schema=@Schema( + type="number", + format="int32", + maximum="1", + minimum="2", + multipleOf="3", + pattern="4", + maxLength=1, + minLength=2, + maxItems=3, + minItems=4, + maxProperties=5, + minProperties=6, + exclusiveMaximum=true, + exclusiveMinimum=true, + uniqueItems=true, + _default={"c1","c2"}, + _enum="e1,e2", + items=@Items( + type="integer", + format="int64", + collectionFormat="ssv", + maximum="5", + minimum="6", + multipleOf="7", + pattern="8", + maxLength=5, + minLength=6, + maxItems=7, + minItems=8, + exclusiveMaximum=false, + exclusiveMinimum=false, + uniqueItems=false, + _default={"c3","c4"}, + _enum="e3,e4", + items=@SubItems( + type="string", + format="float", + collectionFormat="tsv", + maximum="9", + minimum="10", + multipleOf="11", + pattern="12", + maxLength=9, + minLength=10, + maxItems=11, + minItems=12, + exclusiveMaximum=true, + exclusiveMinimum=true, + uniqueItems=true, + _default={"c5","c6"}, + _enum="e5,e6", + items={ + "type:'array',", + "format:'double',", + "collectionFormat:'pipes',", + "maximum:'13',", + "minimum:'14',", + "multipleOf:'15',", + "pattern:'16',", + "maxLength:13,", + "minLength:14,", + "maxItems:15,", + "minItems:16,", + "exclusiveMaximum:false,", + "exclusiveMinimum:false,", + "uniqueItems:false,", + "default:'c7\\nc8',", + "enum:['e7','e8']", + } + ) + ) + ) + ) + public static class A05 {} + + @Test + public void a05_basic_nestedItems_onClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, A05.class).noValidate(true).build(); + + assertEquals(HttpPartSchema.Type.NUMBER, s.getType()); + assertEquals(HttpPartSchema.Format.INT32, s.getFormat()); + assertEquals(1, s.getMaximum()); + assertEquals(2, s.getMinimum()); + assertEquals(3, s.getMultipleOf()); + assertEquals("4", s.getPattern().pattern()); + assertEquals(1, s.getMaxLength().longValue()); + assertEquals(2, s.getMinLength().longValue()); + assertEquals(3, s.getMaxItems().longValue()); + assertEquals(4, s.getMinItems().longValue()); + assertEquals(5, s.getMaxProperties().longValue()); + assertEquals(6, s.getMinProperties().longValue()); + assertTrue(s.getExclusiveMaximum()); + assertTrue(s.getExclusiveMinimum()); + assertTrue(s.getUniqueItems()); + assertObjectEquals("['e1','e2']", s.getEnum()); + assertEquals("c1\nc2", s.getDefault()); + + HttpPartSchema items = s.getItems(); + assertEquals(HttpPartSchema.Type.INTEGER, items.getType()); + assertEquals(HttpPartSchema.Format.INT64, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.SSV, items.getCollectionFormat()); + assertEquals(5, items.getMaximum()); + assertEquals(6, items.getMinimum()); + assertEquals(7, items.getMultipleOf()); + assertEquals("8", items.getPattern().pattern()); + assertEquals(5, items.getMaxLength().longValue()); + assertEquals(6, items.getMinLength().longValue()); + assertEquals(7, items.getMaxItems().longValue()); + assertEquals(8, items.getMinItems().longValue()); + assertNull(items.getExclusiveMaximum()); + assertNull(items.getExclusiveMinimum()); + assertNull(items.getUniqueItems()); + assertObjectEquals("['e3','e4']", items.getEnum()); + assertEquals("c3\nc4", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.STRING, items.getType()); + assertEquals(HttpPartSchema.Format.FLOAT, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.TSV, items.getCollectionFormat()); + assertEquals(9, items.getMaximum()); + assertEquals(10, items.getMinimum()); + assertEquals(11, items.getMultipleOf()); + assertEquals("12", items.getPattern().pattern()); + assertEquals(9, items.getMaxLength().longValue()); + assertEquals(10, items.getMinLength().longValue()); + assertEquals(11, items.getMaxItems().longValue()); + assertEquals(12, items.getMinItems().longValue()); + assertTrue(items.getExclusiveMaximum()); + assertTrue(items.getExclusiveMinimum()); + assertTrue(items.getUniqueItems()); + assertObjectEquals("['e5','e6']", items.getEnum()); + assertEquals("c5\nc6", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.ARRAY, items.getType()); + assertEquals(HttpPartSchema.Format.DOUBLE, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.PIPES, items.getCollectionFormat()); + assertEquals(13, items.getMaximum()); + assertEquals(14, items.getMinimum()); + assertEquals(15, items.getMultipleOf()); + assertEquals("16", items.getPattern().pattern()); + assertEquals(13, items.getMaxLength().longValue()); + assertEquals(14, items.getMinLength().longValue()); + assertEquals(15, items.getMaxItems().longValue()); + assertEquals(16, items.getMinItems().longValue()); + assertFalse(items.getExclusiveMaximum()); + assertFalse(items.getExclusiveMinimum()); + assertFalse(items.getUniqueItems()); + assertObjectEquals("['e7','e8']", items.getEnum()); + assertEquals("c7\nc8", items.getDefault()); + + assertObjectEquals( + "{schema:{'default':'c1\\nc2','enum':['e1','e2'],exclusiveMaximum:true,exclusiveMinimum:true,format:'int32',items:{collectionFormat:'ssv','default':'c3\\nc4','enum':['e3','e4'],format:'int64',items:{collectionFormat:'tsv','default':'c5\\nc6','enum':['e5','e6'],exclusiveMaximum:true,exclusiveMinimum:true,format:'float',items:{type:'array',format:'double',collectionFormat:'pipes',maximum:'13',minimum:'14',multipleOf:'15',pattern:'16',maxLength:13,minLength:14,maxItems:15,minItems:16,exc [...] + s.getApi() + ); + } + + //----------------------------------------------------------------------------------------------------------------- + // String input validations. + //----------------------------------------------------------------------------------------------------------------- + + @Body(required=true) + public static class B01a {} + + @Test + public void b01a_required() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, B01a.class).build(); + + s.validateInput("x"); + + try { + s.validateInput(null); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("No value specified.", e.getLocalizedMessage()); + } + try { + s.validateInput(""); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Empty value not allowed.", e.getLocalizedMessage()); + } + } + + @Body( + schema=@Schema( + pattern="x.*" + ) + ) + public static class B02a {} + + @Test + public void b02a_pattern() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, B02a.class).build(); + + s.validateInput("x"); + s.validateInput("xx"); + + try { + s.validateInput(""); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match expected pattern. Must match pattern: x.*", e.getLocalizedMessage()); + } + try { + s.validateInput("y"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match expected pattern. Must match pattern: x.*", e.getLocalizedMessage()); + } + } + + @Body( + schema=@Schema( + items=@Items( + pattern="w.*", + items=@SubItems( + pattern="x.*", + items={ + "pattern:'y.*',", + "items:{pattern:'z.*'}" + } + ) + ) + ) + ) + public static class B02b {} + + @Body( + schema=@Schema( + minLength=2, maxLength=3 + ) + ) + public static class B03a {} + + @Test + public void b03a_length() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, B03a.class).build(); + s.validateInput("12"); + s.validateInput("123"); + s.validateInput(null); + try { + s.validateInput("1"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + } + + @Body( + schema=@Schema( + items=@Items( + minLength=2, maxLength=3, + items=@SubItems( + minLength=3, maxLength=4, + items={ + "minLength:4,maxLength:5,", + "items:{minLength:5,maxLength:6}" + } + ) + ) + ) + ) + public static class B03b {} + + @Test + public void b03b_length_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, B03b.class).build(); + + s.getItems().validateInput("12"); + s.getItems().getItems().validateInput("123"); + s.getItems().getItems().getItems().validateInput("1234"); + s.getItems().getItems().getItems().getItems().validateInput("12345"); + + s.getItems().validateInput("123"); + s.getItems().getItems().validateInput("1234"); + s.getItems().getItems().getItems().validateInput("12345"); + s.getItems().getItems().getItems().getItems().validateInput("123456"); + + s.getItems().validateInput(null); + s.getItems().getItems().validateInput(null); + s.getItems().getItems().getItems().validateInput(null); + s.getItems().getItems().getItems().getItems().validateInput(null); + + try { + s.getItems().validateInput("1"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("12"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("123"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("12345"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("123456"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("1234567"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + } + + @Body(schema=@Schema(_enum="X,Y")) + public static class B04a {} + + @Test + public void b04a_enum() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, B04a.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @Body(schema=@Schema(_enum=" X , Y ")) + public static class B04b {} + + @Test + public void b04b_enum() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, B04b.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @Body(schema=@Schema(_enum="['X','Y']")) + public static class B04c {} + + @Test + public void b04c_enum_json() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, B04c.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @Body( + schema=@Schema( + items=@Items( + _enum="['W']", + items=@SubItems( + _enum="['X']", + items={ + "enum:['Y'],", + "items:{enum:['Z']}" + } + ) + ) + ) + ) + public static class B04d {} + + @Test + public void b04d_enum_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, B04d.class).build(); + + s.getItems().validateInput("W"); + s.getItems().getItems().validateInput("X"); + s.getItems().getItems().getItems().validateInput("Y"); + s.getItems().getItems().getItems().getItems().validateInput("Z"); + + try { + s.getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['W']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['Y']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['Z']", e.getLocalizedMessage()); + } + } + + //----------------------------------------------------------------------------------------------------------------- + // Numeric validations + //----------------------------------------------------------------------------------------------------------------- + + @Body(schema=@Schema(minimum="10", maximum="100")) + public static class C01a {} + + @Test + public void c01a_minmax_ints() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, C01a.class).build(); + s.validateOutput(10, BeanContext.DEFAULT); + s.validateOutput(100, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(9, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Body( + schema=@Schema( + items=@Items( + minimum="10", maximum="100", + items=@SubItems( + minimum="100", maximum="1000", + items={ + "minimum:1000,maximum:10000,", + "items:{minimum:10000,maximum:100000}" + } + ) + ) + ) + ) + public static class C01b {} + + @Test + public void c01b_minmax_ints_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, C01b.class).build(); + + s.getItems().validateOutput(10, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + + s.getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(9, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(99, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(999, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(9999, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Body(schema=@Schema(minimum="10", maximum="100", exclusiveMinimum=true, exclusiveMaximum=true)) + public static class C02a {} + + @Test + public void c02a_minmax_exclusive() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, C02a.class).build(); + s.validateOutput(11, BeanContext.DEFAULT); + s.validateOutput(99, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Body( + schema=@Schema( + items=@Items( + minimum="10", maximum="100", exclusiveMinimum=true, exclusiveMaximum=true, + items=@SubItems( + minimum="100", maximum="1000", exclusiveMinimum=true, exclusiveMaximum=true, + items={ + "minimum:1000,maximum:10000,exclusiveMinimum:true,exclusiveMaximum:true,", + "items:{minimum:10000,maximum:100000,exclusiveMinimum:true,exclusiveMaximum:true}" + } + ) + ) + ) + ) + public static class C02b {} + + @Test + public void c02b_minmax_exclusive_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, C02b.class).build(); + + s.getItems().validateOutput(11, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(101, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + + s.getItems().validateOutput(99, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(999, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(9999, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(99999, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Body(schema=@Schema(minimum="10.1", maximum="100.1")) + public static class C03a {} + + @Test + public void c03_minmax_floats() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, C03a.class).build(); + s.validateOutput(10.1f, BeanContext.DEFAULT); + s.validateOutput(100.1f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Body( + schema=@Schema( + items=@Items( + minimum="10.1", maximum="100.1", + items=@SubItems( + minimum="100.1", maximum="1000.1", + items={ + "minimum:1000.1,maximum:10000.1,", + "items:{minimum:10000.1,maximum:100000.1}" + } + ) + ) + ) + ) + public static class C03b {} + + @Test + public void c03b_minmax_floats_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, C03b.class).build(); + + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + + s.getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000.1f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Body(schema=@Schema(minimum="10.1", maximum="100.1", exclusiveMinimum=true, exclusiveMaximum=true)) + public static class C04a {} + + @Test + public void c04a_minmax_floats_exclusive() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, C04a.class).build(); + s.validateOutput(10.2f, BeanContext.DEFAULT); + s.validateOutput(100f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Body( + schema=@Schema( + items=@Items( + minimum="10.1", maximum="100.1", exclusiveMinimum=true, exclusiveMaximum=true, + items=@SubItems( + minimum="100.1", maximum="1000.1", exclusiveMinimum=true, exclusiveMaximum=true, + items={ + "minimum:1000.1,maximum:10000.1,exclusiveMinimum:true,exclusiveMaximum:true,", + "items:{minimum:10000.1,maximum:100000.1,exclusiveMinimum:true,exclusiveMaximum:true}" + } + ) + ) + ) + ) + public static class C04b {} + + @Test + public void c04b_minmax_floats_exclusive_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, C04b.class).build(); + + s.getItems().validateOutput(10.2f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + + s.getItems().validateOutput(100f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Body(schema=@Schema(multipleOf="10")) + public static class C05a {} + + @Test + public void c05a_multipleOf() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, C05a.class).build(); + s.validateOutput(0, BeanContext.DEFAULT); + s.validateOutput(10, BeanContext.DEFAULT); + s.validateOutput(20, BeanContext.DEFAULT); + s.validateOutput(10f, BeanContext.DEFAULT); + s.validateOutput(20f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(11, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @Body( + schema=@Schema( + items=@Items( + multipleOf="10", + items=@SubItems( + multipleOf="100", + items={ + "multipleOf:1000,", + "items:{multipleOf:10000}" + } + ) + ) + ) + ) + public static class C05b {} + + @Test + public void c05b_multipleOf_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, C05b.class).build(); + + s.getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + + s.getItems().validateOutput(10, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + + s.getItems().validateOutput(20, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000, BeanContext.DEFAULT); + + s.getItems().validateOutput(10f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + + s.getItems().validateOutput(20f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(11, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @Body(schema=@Schema(multipleOf="10.1")) + public static class C06a {} + + @Test + public void c06a_multipleOf_floats() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, C06a.class).build(); + s.validateOutput(0, BeanContext.DEFAULT); + s.validateOutput(10.1f, BeanContext.DEFAULT); + s.validateOutput(20.2f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @Body( + schema=@Schema( + items=@Items( + multipleOf="10.1", + items=@SubItems( + multipleOf="100.1", + items={ + "multipleOf:1000.1,", + "items:{multipleOf:10000.1}" + } + ) + ) + ) + ) + public static class C06b {} + + @Test + public void c06b_multipleOf_floats_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, C06b.class).build(); + + s.getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + + s.getItems().validateOutput(20.2f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000.2f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + //----------------------------------------------------------------------------------------------------------------- + // Collections/Array validations + //----------------------------------------------------------------------------------------------------------------- + + @Body( + schema=@Schema( + items=@Items( + uniqueItems=true, + items=@SubItems( + uniqueItems=true, + items={ + "uniqueItems:true,", + "items:{uniqueItems:true}" + } + ) + ) + ) + ) + public static class D01 {} + + @Test + public void d01a_uniqueItems_arrays() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, D01.class).build(); + + String[] good = split("a,b"), bad = split("a,a"); + + s.getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().validateOutput(null, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + } + + @Test + public void d01b_uniqueItems_collections() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, D01.class).build(); + + AList + good = new AList().appendAll(split("a,b")), + bad = new AList().appendAll(split("a,a")); + + s.getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().validateOutput(null, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + } + + @Body( + schema=@Schema( + items=@Items( + minItems=1, maxItems=2, + items=@SubItems( + minItems=2, maxItems=3, + items={ + "minItems:3,maxItems:4,", + "items:{minItems:4,maxItems:5}" + } + ) + ) + ) + ) + public static class D02 {} + + @Test + public void d02a_minMaxItems_arrays() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Body.class, D02.class).build(); + + s.getItems().validateOutput(split("1"), BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + + s.getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4,5"), BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(new String[0], BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(split("1"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(split("1,2,3,4,5"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4,5,6"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + } +} \ No newline at end of file diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_FormData.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_FormData.java new file mode 100644 index 0000000..d6f3e2a --- /dev/null +++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_FormData.java @@ -0,0 +1,1419 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.httppart; + +import static org.junit.Assert.*; + +import static org.apache.juneau.testutils.TestUtils.*; +import static org.apache.juneau.internal.StringUtils.*; + +import org.apache.juneau.*; +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.utils.*; +import org.junit.*; + +public class HttpPartSchemaTest_FormData { + + //----------------------------------------------------------------------------------------------------------------- + // Basic test + //----------------------------------------------------------------------------------------------------------------- + @Test + public void testBasic() throws Exception { + HttpPartSchema.create().build(); + } + + //----------------------------------------------------------------------------------------------------------------- + // @FormData + //----------------------------------------------------------------------------------------------------------------- + + @FormData("x") + public static class A01 {} + + @Test + public void a01_value() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, A01.class).build(); + assertEquals("x", s.getName()); + assertObjectEquals("{}", s.getApi()); + } + + @FormData( + name="x", + type="number", + format="int32", + collectionFormat="csv", + maximum="1", + minimum="2", + multipleOf="3", + pattern="4", + maxLength=1, + minLength=2, + maxItems=3, + minItems=4, + exclusiveMaximum=true, + exclusiveMinimum=true, + uniqueItems=true, + required=true, + skipIfEmpty=true, + description={"b1","b2"}, + _default={"c1","c2"}, + items=@Items($ref="d1"), + _enum="e1,e2,e3", + example="f1", + api="{g1:true}" + ) + public static class A02 {} + + @Test + public void a02_basic_onClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, A02.class).noValidate(true).build(); + assertEquals("x", s.getName()); + assertEquals(HttpPartSchema.Type.NUMBER, s.getType()); + assertEquals(HttpPartSchema.Format.INT32, s.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.CSV, s.getCollectionFormat()); + assertEquals(1, s.getMaximum()); + assertEquals(2, s.getMinimum()); + assertEquals(3, s.getMultipleOf()); + assertEquals("4", s.getPattern().pattern()); + assertEquals(1, s.getMaxLength().longValue()); + assertEquals(2, s.getMinLength().longValue()); + assertEquals(3, s.getMaxItems().longValue()); + assertEquals(4, s.getMinItems().longValue()); + assertTrue(s.getExclusiveMaximum()); + assertTrue(s.getExclusiveMinimum()); + assertTrue(s.getUniqueItems()); + assertTrue(s.getRequired()); + assertTrue(s.getSkipIfEmpty()); + assertObjectEquals("['e1','e2','e3']", s.getEnum()); + assertEquals("c1\nc2", s.getDefault()); + assertObjectEquals("{collectionFormat:'csv','default':'c1\\nc2',description:'b1\\nb2','enum':['e1','e2','e3'],example:'f1',exclusiveMaximum:true,exclusiveMinimum:true,format:'int32',items:{'$ref':'d1'},maximum:'1',maxItems:3,maxLength:1,minimum:'2',minItems:4,minLength:2,multipleOf:'3',pattern:'4',required:true,type:'number',uniqueItems:true,_value:'{g1:true}'}", s.getApi()); + } + + public static class A03 { + public void a( + @FormData( + name="x", + type="number", + format="int32", + collectionFormat="csv", + maximum="1", + minimum="2", + multipleOf="3", + pattern="4", + maxLength=1, + minLength=2, + maxItems=3, + minItems=4, + exclusiveMaximum=true, + exclusiveMinimum=true, + uniqueItems=true, + required=true, + skipIfEmpty=true, + description={"b1","b2"}, + _default={"c1","c2"}, + items=@Items($ref="d1"), + _enum="e1,e2,e3", + example="f1", + api="{g1:true}" + ) String x + ) { + + } + } + + @Test + public void a03_basic_onParameter() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, A03.class.getMethod("a", String.class), 0).noValidate(true).build(); + assertEquals("x", s.getName()); + assertEquals(HttpPartSchema.Type.NUMBER, s.getType()); + assertEquals(HttpPartSchema.Format.INT32, s.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.CSV, s.getCollectionFormat()); + assertEquals(1, s.getMaximum()); + assertEquals(2, s.getMinimum()); + assertEquals(3, s.getMultipleOf()); + assertEquals("4", s.getPattern().pattern()); + assertEquals(1, s.getMaxLength().longValue()); + assertEquals(2, s.getMinLength().longValue()); + assertEquals(3, s.getMaxItems().longValue()); + assertEquals(4, s.getMinItems().longValue()); + assertTrue(s.getExclusiveMaximum()); + assertTrue(s.getExclusiveMinimum()); + assertTrue(s.getUniqueItems()); + assertTrue(s.getRequired()); + assertTrue(s.getSkipIfEmpty()); + assertObjectEquals("['e1','e2','e3']", s.getEnum()); + assertEquals("c1\nc2", s.getDefault()); + assertObjectEquals("{collectionFormat:'csv','default':'c1\\nc2',description:'b1\\nb2','enum':['e1','e2','e3'],example:'f1',exclusiveMaximum:true,exclusiveMinimum:true,format:'int32',items:{'$ref':'d1'},maximum:'1',maxItems:3,maxLength:1,minimum:'2',minItems:4,minLength:2,multipleOf:'3',pattern:'4',required:true,type:'number',uniqueItems:true,_value:'{g1:true}'}", s.getApi()); + } + + public static class A04 { + public void a( + @FormData( + name="y", + type="integer", + format="int64", + collectionFormat="ssv", + maximum="5", + minimum="6", + multipleOf="7", + pattern="8", + maxLength=5, + minLength=6, + maxItems=7, + minItems=8, + exclusiveMaximum=false, + exclusiveMinimum=false, + uniqueItems=false, + required=false, + skipIfEmpty=false, + description={"b3","b3"}, + _default={"c3","c4"}, + items=@Items($ref="d2"), + _enum="e4,e5,e6", + example="f2", + api="{g2:true}" + ) A01 x + ) { + + } + } + + @Test + public void a04_basic_onParameterAndClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, A04.class.getMethod("a", A01.class), 0).noValidate(true).build(); + assertEquals("y", s.getName()); + assertEquals(HttpPartSchema.Type.INTEGER, s.getType()); + assertEquals(HttpPartSchema.Format.INT64, s.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.SSV, s.getCollectionFormat()); + assertEquals(5, s.getMaximum()); + assertEquals(6, s.getMinimum()); + assertEquals(7, s.getMultipleOf()); + assertEquals("8", s.getPattern().pattern()); + assertEquals(5, s.getMaxLength().longValue()); + assertEquals(6, s.getMinLength().longValue()); + assertEquals(7, s.getMaxItems().longValue()); + assertEquals(8, s.getMinItems().longValue()); + assertNull(s.getExclusiveMaximum()); + assertNull(s.getExclusiveMinimum()); + assertNull(s.getUniqueItems()); + assertNull(s.getRequired()); + assertNull(s.getSkipIfEmpty()); + assertObjectEquals("['e4','e5','e6']", s.getEnum()); + assertEquals("c3\nc4", s.getDefault()); + assertObjectEquals("{collectionFormat:'ssv','default':'c3\\nc4',description:'b3\\nb3','enum':['e4','e5','e6'],example:'f2',format:'int64',items:{'$ref':'d2'},maximum:'5',maxItems:7,maxLength:5,minimum:'6',minItems:8,minLength:6,multipleOf:'7',pattern:'8',type:'integer',_value:'{g2:true}'}", s.getApi()); + } + + @FormData( + name="x", + items=@Items( + type="number", + format="int32", + collectionFormat="csv", + maximum="1", + minimum="2", + multipleOf="3", + pattern="4", + maxLength=1, + minLength=2, + maxItems=3, + minItems=4, + exclusiveMaximum=true, + exclusiveMinimum=true, + uniqueItems=true, + _default={"c1","c2"}, + _enum="e1,e2", + items=@SubItems( + type="integer", + format="int64", + collectionFormat="ssv", + maximum="5", + minimum="6", + multipleOf="7", + pattern="8", + maxLength=5, + minLength=6, + maxItems=7, + minItems=8, + exclusiveMaximum=false, + exclusiveMinimum=false, + uniqueItems=false, + _default={"c3","c4"}, + _enum="e3,e4", + items={ + "type:'string',", + "format:'float',", + "collectionFormat:'tsv',", + "maximum:'9',", + "minimum:'10',", + "multipleOf:'11',", + "pattern:'12',", + "maxLength:9,", + "minLength:10,", + "maxItems:11,", + "minItems:12,", + "exclusiveMaximum:true,", + "exclusiveMinimum:true,", + "uniqueItems:true,", + "default:'c5\\nc6',", + "enum:['e5','e6'],", + "items:{", + "type:'array',", + "format:'double',", + "collectionFormat:'pipes',", + "maximum:'13',", + "minimum:'14',", + "multipleOf:'15',", + "pattern:'16',", + "maxLength:13,", + "minLength:14,", + "maxItems:15,", + "minItems:16,", + "exclusiveMaximum:false,", + "exclusiveMinimum:false,", + "uniqueItems:false,", + "default:'c7\\nc8',", + "enum:['e7','e8']", + "}" + } + ) + ) + ) + public static class A05 {} + + @Test + public void a05_basic_nestedItems_onClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, A05.class).noValidate(true).build(); + assertEquals("x", s.getName()); + + HttpPartSchema items = s.getItems(); + assertEquals(HttpPartSchema.Type.NUMBER, items.getType()); + assertEquals(HttpPartSchema.Format.INT32, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.CSV, items.getCollectionFormat()); + assertEquals(1, items.getMaximum()); + assertEquals(2, items.getMinimum()); + assertEquals(3, items.getMultipleOf()); + assertEquals("4", items.getPattern().pattern()); + assertEquals(1, items.getMaxLength().longValue()); + assertEquals(2, items.getMinLength().longValue()); + assertEquals(3, items.getMaxItems().longValue()); + assertEquals(4, items.getMinItems().longValue()); + assertTrue(items.getExclusiveMaximum()); + assertTrue(items.getExclusiveMinimum()); + assertTrue(items.getUniqueItems()); + assertObjectEquals("['e1','e2']", items.getEnum()); + assertEquals("c1\nc2", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.INTEGER, items.getType()); + assertEquals(HttpPartSchema.Format.INT64, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.SSV, items.getCollectionFormat()); + assertEquals(5, items.getMaximum()); + assertEquals(6, items.getMinimum()); + assertEquals(7, items.getMultipleOf()); + assertEquals("8", items.getPattern().pattern()); + assertEquals(5, items.getMaxLength().longValue()); + assertEquals(6, items.getMinLength().longValue()); + assertEquals(7, items.getMaxItems().longValue()); + assertEquals(8, items.getMinItems().longValue()); + assertNull(items.getExclusiveMaximum()); + assertNull(items.getExclusiveMinimum()); + assertNull(items.getUniqueItems()); + assertObjectEquals("['e3','e4']", items.getEnum()); + assertEquals("c3\nc4", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.STRING, items.getType()); + assertEquals(HttpPartSchema.Format.FLOAT, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.TSV, items.getCollectionFormat()); + assertEquals(9, items.getMaximum()); + assertEquals(10, items.getMinimum()); + assertEquals(11, items.getMultipleOf()); + assertEquals("12", items.getPattern().pattern()); + assertEquals(9, items.getMaxLength().longValue()); + assertEquals(10, items.getMinLength().longValue()); + assertEquals(11, items.getMaxItems().longValue()); + assertEquals(12, items.getMinItems().longValue()); + assertTrue(items.getExclusiveMaximum()); + assertTrue(items.getExclusiveMinimum()); + assertTrue(items.getUniqueItems()); + assertObjectEquals("['e5','e6']", items.getEnum()); + assertEquals("c5\nc6", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.ARRAY, items.getType()); + assertEquals(HttpPartSchema.Format.DOUBLE, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.PIPES, items.getCollectionFormat()); + assertEquals(13, items.getMaximum()); + assertEquals(14, items.getMinimum()); + assertEquals(15, items.getMultipleOf()); + assertEquals("16", items.getPattern().pattern()); + assertEquals(13, items.getMaxLength().longValue()); + assertEquals(14, items.getMinLength().longValue()); + assertEquals(15, items.getMaxItems().longValue()); + assertEquals(16, items.getMinItems().longValue()); + assertFalse(items.getExclusiveMaximum()); + assertFalse(items.getExclusiveMinimum()); + assertFalse(items.getUniqueItems()); + assertObjectEquals("['e7','e8']", items.getEnum()); + assertEquals("c7\nc8", items.getDefault()); + + assertObjectEquals( + "{items:{collectionFormat:'csv','default':'c1\\nc2','enum':['e1','e2'],format:'int32',exclusiveMaximum:true,exclusiveMinimum:true,items:{collectionFormat:'ssv','default':'c3\\nc4','enum':['e3','e4'],format:'int64',items:{type:'string',format:'float',collectionFormat:'tsv',maximum:'9',minimum:'10',multipleOf:'11',pattern:'12',maxLength:9,minLength:10,maxItems:11,minItems:12,exclusiveMaximum:true,exclusiveMinimum:true,uniqueItems:true,'default':'c5\\nc6','enum':['e5','e6'],items:{type:' [...] + s.getApi() + ); + } + + //----------------------------------------------------------------------------------------------------------------- + // String input validations. + //----------------------------------------------------------------------------------------------------------------- + + @FormData(required=true) + public static class B01a {} + + @Test + public void b01a_required() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, B01a.class).build(); + + s.validateInput("x"); + + try { + s.validateInput(null); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("No value specified.", e.getLocalizedMessage()); + } + try { + s.validateInput(""); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Empty value not allowed.", e.getLocalizedMessage()); + } + } + + @FormData(allowEmptyValue=true) + public static class B01b {} + + @Test + public void b01b_allowEmptyValue() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, B01b.class).build(); + + s.validateInput(""); + s.validateInput(null); + } + + @FormData(required=true,allowEmptyValue=true) + public static class B01c {} + + @Test + public void b01b_required_allowEmptyValue() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, B01c.class).build(); + + s.validateInput(""); + + try { + s.validateInput(null); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("No value specified.", e.getLocalizedMessage()); + } + } + + @FormData(pattern="x.*") + public static class B02a {} + + @Test + public void b02a_pattern() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, B02a.class).build(); + s.validateInput("x"); + s.validateInput("xx"); + try { + s.validateInput("y"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match expected pattern. Must match pattern: x.*", e.getLocalizedMessage()); + } + try { + s.validateInput("yx"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match expected pattern. Must match pattern: x.*", e.getLocalizedMessage()); + } + try { + s.validateInput(""); // Empty headers are never allowed. + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Empty value not allowed.", e.getLocalizedMessage()); + } + } + + @FormData(minLength=2, maxLength=3) + public static class B03a {} + + @Test + public void b03a_length() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, B03a.class).build(); + s.validateInput("12"); + s.validateInput("123"); + s.validateInput(null); + try { + s.validateInput("1"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + } + + @FormData( + items=@Items( + minLength=2, maxLength=3, + items=@SubItems( + minLength=3, maxLength=4, + items={ + "minLength:4,maxLength:5,", + "items:{minLength:5,maxLength:6}" + } + ) + ) + ) + public static class B03b {} + + @Test + public void b03b_length_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, B03b.class).build(); + + s.getItems().validateInput("12"); + s.getItems().getItems().validateInput("123"); + s.getItems().getItems().getItems().validateInput("1234"); + s.getItems().getItems().getItems().getItems().validateInput("12345"); + + s.getItems().validateInput("123"); + s.getItems().getItems().validateInput("1234"); + s.getItems().getItems().getItems().validateInput("12345"); + s.getItems().getItems().getItems().getItems().validateInput("123456"); + + s.getItems().validateInput(null); + s.getItems().getItems().validateInput(null); + s.getItems().getItems().getItems().validateInput(null); + s.getItems().getItems().getItems().getItems().validateInput(null); + + try { + s.getItems().validateInput("1"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("12"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("123"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("12345"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("123456"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("1234567"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + } + + @FormData(_enum="X,Y") + public static class B04a {} + + @Test + public void b04a_enum() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, B04a.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @FormData(_enum=" X , Y ") + public static class B04b {} + + @Test + public void b04b_enum() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, B04b.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @FormData(_enum="['X','Y']") + public static class B04c {} + + @Test + public void b04c_enum_json() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, B04c.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @FormData( + items=@Items( + _enum="['W']", + items=@SubItems( + _enum="['X']", + items={ + "enum:['Y'],", + "items:{enum:['Z']}" + } + ) + ) + ) + public static class B04d {} + + @Test + public void b04d_enum_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, B04d.class).build(); + + s.getItems().validateInput("W"); + s.getItems().getItems().validateInput("X"); + s.getItems().getItems().getItems().validateInput("Y"); + s.getItems().getItems().getItems().getItems().validateInput("Z"); + + try { + s.getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['W']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['Y']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['Z']", e.getLocalizedMessage()); + } + } + + //----------------------------------------------------------------------------------------------------------------- + // Numeric validations + //----------------------------------------------------------------------------------------------------------------- + + @FormData(minimum="10", maximum="100") + public static class C01a {} + + @Test + public void c01a_minmax_ints() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, C01a.class).build(); + s.validateOutput(10, BeanContext.DEFAULT); + s.validateOutput(100, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(9, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @FormData( + items=@Items( + minimum="10", maximum="100", + items=@SubItems( + minimum="100", maximum="1000", + items={ + "minimum:1000,maximum:10000,", + "items:{minimum:10000,maximum:100000}" + } + ) + ) + ) + public static class C01b {} + + @Test + public void c01b_minmax_ints_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, C01b.class).build(); + + s.getItems().validateOutput(10, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + + s.getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(9, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(99, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(999, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(9999, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @FormData(minimum="10", maximum="100", exclusiveMinimum=true, exclusiveMaximum=true) + public static class C02a {} + + @Test + public void c02a_minmax_exclusive() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, C02a.class).build(); + s.validateOutput(11, BeanContext.DEFAULT); + s.validateOutput(99, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @FormData( + items=@Items( + minimum="10", maximum="100", exclusiveMinimum=true, exclusiveMaximum=true, + items=@SubItems( + minimum="100", maximum="1000", exclusiveMinimum=true, exclusiveMaximum=true, + items={ + "minimum:1000,maximum:10000,exclusiveMinimum:true,exclusiveMaximum:true,", + "items:{minimum:10000,maximum:100000,exclusiveMinimum:true,exclusiveMaximum:true}" + } + ) + ) + ) + public static class C02b {} + + @Test + public void c02b_minmax_exclusive_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, C02b.class).build(); + + s.getItems().validateOutput(11, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(101, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + + s.getItems().validateOutput(99, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(999, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(9999, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(99999, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @FormData(minimum="10.1", maximum="100.1") + public static class C03a {} + + @Test + public void c03_minmax_floats() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, C03a.class).build(); + s.validateOutput(10.1f, BeanContext.DEFAULT); + s.validateOutput(100.1f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @FormData( + items=@Items( + minimum="10.1", maximum="100.1", + items=@SubItems( + minimum="100.1", maximum="1000.1", + items={ + "minimum:1000.1,maximum:10000.1,", + "items:{minimum:10000.1,maximum:100000.1}" + } + ) + ) + ) + public static class C03b {} + + @Test + public void c03b_minmax_floats_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, C03b.class).build(); + + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + + s.getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000.1f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @FormData(minimum="10.1", maximum="100.1", exclusiveMinimum=true, exclusiveMaximum=true) + public static class C04a {} + + @Test + public void c04a_minmax_floats_exclusive() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, C04a.class).build(); + s.validateOutput(10.2f, BeanContext.DEFAULT); + s.validateOutput(100f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @FormData( + items=@Items( + minimum="10.1", maximum="100.1", exclusiveMinimum=true, exclusiveMaximum=true, + items=@SubItems( + minimum="100.1", maximum="1000.1", exclusiveMinimum=true, exclusiveMaximum=true, + items={ + "minimum:1000.1,maximum:10000.1,exclusiveMinimum:true,exclusiveMaximum:true,", + "items:{minimum:10000.1,maximum:100000.1,exclusiveMinimum:true,exclusiveMaximum:true}" + } + ) + ) + ) + public static class C04b {} + + @Test + public void c04b_minmax_floats_exclusive_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, C04b.class).build(); + + s.getItems().validateOutput(10.2f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + + s.getItems().validateOutput(100f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @FormData(multipleOf="10") + public static class C05a {} + + @Test + public void c05a_multipleOf() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, C05a.class).build(); + s.validateOutput(0, BeanContext.DEFAULT); + s.validateOutput(10, BeanContext.DEFAULT); + s.validateOutput(20, BeanContext.DEFAULT); + s.validateOutput(10f, BeanContext.DEFAULT); + s.validateOutput(20f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(11, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @FormData( + items=@Items( + multipleOf="10", + items=@SubItems( + multipleOf="100", + items={ + "multipleOf:1000,", + "items:{multipleOf:10000}" + } + ) + ) + ) + public static class C05b {} + + @Test + public void c05b_multipleOf_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, C05b.class).build(); + + s.getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + + s.getItems().validateOutput(10, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + + s.getItems().validateOutput(20, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000, BeanContext.DEFAULT); + + s.getItems().validateOutput(10f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + + s.getItems().validateOutput(20f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(11, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @FormData(multipleOf="10.1") + public static class C06a {} + + @Test + public void c06a_multipleOf_floats() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, C06a.class).build(); + s.validateOutput(0, BeanContext.DEFAULT); + s.validateOutput(10.1f, BeanContext.DEFAULT); + s.validateOutput(20.2f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @FormData( + items=@Items( + multipleOf="10.1", + items=@SubItems( + multipleOf="100.1", + items={ + "multipleOf:1000.1,", + "items:{multipleOf:10000.1}" + } + ) + ) + ) + public static class C06b {} + + @Test + public void c06b_multipleOf_floats_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, C06b.class).build(); + + s.getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + + s.getItems().validateOutput(20.2f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000.2f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + //----------------------------------------------------------------------------------------------------------------- + // Collections/Array validations + //----------------------------------------------------------------------------------------------------------------- + + @FormData( + items=@Items( + uniqueItems=true, + items=@SubItems( + uniqueItems=true, + items={ + "uniqueItems:true,", + "items:{uniqueItems:true}" + } + ) + ) + + ) + public static class D01 {} + + @Test + public void d01a_uniqueItems_arrays() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, D01.class).build(); + + String[] good = split("a,b"), bad = split("a,a"); + + s.getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().validateOutput(null, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + } + + @Test + public void d01b_uniqueItems_collections() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, D01.class).build(); + + AList + good = new AList().appendAll(split("a,b")), + bad = new AList().appendAll(split("a,a")); + + s.getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().validateOutput(null, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + } + + @FormData( + items=@Items( + minItems=1, maxItems=2, + items=@SubItems( + minItems=2, maxItems=3, + items={ + "minItems:3,maxItems:4,", + "items:{minItems:4,maxItems:5}" + } + ) + ) + + ) + public static class D02 {} + + @Test + public void d02a_minMaxItems_arrays() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(FormData.class, D02.class).build(); + + s.getItems().validateOutput(split("1"), BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + + s.getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4,5"), BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(new String[0], BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(split("1"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(split("1,2,3,4,5"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4,5,6"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + } +} \ No newline at end of file diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Header.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Header.java new file mode 100644 index 0000000..62c9dde --- /dev/null +++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Header.java @@ -0,0 +1,1389 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.httppart; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.apache.juneau.testutils.TestUtils.*; +import static org.apache.juneau.internal.StringUtils.*; + +import org.apache.juneau.*; +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.utils.*; +import org.junit.*; + +public class HttpPartSchemaTest_Header { + + //----------------------------------------------------------------------------------------------------------------- + // Basic test + //----------------------------------------------------------------------------------------------------------------- + @Test + public void testBasic() throws Exception { + HttpPartSchema.create().build(); + } + + //----------------------------------------------------------------------------------------------------------------- + // @Header + //----------------------------------------------------------------------------------------------------------------- + + @Header("x") + public static class A01 {} + + @Test + public void a01_value() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, A01.class).build(); + assertEquals("x", s.getName()); + assertObjectEquals("{}", s.getApi()); + } + + @Header( + name="x", + type="number", + format="int32", + collectionFormat="csv", + maximum="1", + minimum="2", + multipleOf="3", + pattern="4", + maxLength=1, + minLength=2, + maxItems=3, + minItems=4, + exclusiveMaximum=true, + exclusiveMinimum=true, + uniqueItems=true, + required=true, + skipIfEmpty=true, + description={"b1","b2"}, + _default={"c1","c2"}, + items=@Items($ref="d1"), + _enum="e1,e2,e3", + example="f1", + api="{g1:true}" + ) + public static class A02 {} + + @Test + public void a02_basic_onClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, A02.class).noValidate(true).build(); + assertEquals("x", s.getName()); + assertEquals(HttpPartSchema.Type.NUMBER, s.getType()); + assertEquals(HttpPartSchema.Format.INT32, s.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.CSV, s.getCollectionFormat()); + assertEquals(1, s.getMaximum()); + assertEquals(2, s.getMinimum()); + assertEquals(3, s.getMultipleOf()); + assertEquals("4", s.getPattern().pattern()); + assertEquals(1, s.getMaxLength().longValue()); + assertEquals(2, s.getMinLength().longValue()); + assertEquals(3, s.getMaxItems().longValue()); + assertEquals(4, s.getMinItems().longValue()); + assertTrue(s.getExclusiveMaximum()); + assertTrue(s.getExclusiveMinimum()); + assertTrue(s.getUniqueItems()); + assertTrue(s.getRequired()); + assertTrue(s.getSkipIfEmpty()); + assertObjectEquals("['e1','e2','e3']", s.getEnum()); + assertEquals("c1\nc2", s.getDefault()); + assertObjectEquals("{collectionFormat:'csv','default':'c1\\nc2',description:'b1\\nb2','enum':['e1','e2','e3'],example:'f1',exclusiveMaximum:true,exclusiveMinimum:true,format:'int32',items:{'$ref':'d1'},maximum:'1',maxItems:3,maxLength:1,minimum:'2',minItems:4,minLength:2,multipleOf:'3',pattern:'4',required:true,type:'number',uniqueItems:true,_value:'{g1:true}'}", s.getApi()); + } + + public static class A03 { + public void a( + @Header( + name="x", + type="number", + format="int32", + collectionFormat="csv", + maximum="1", + minimum="2", + multipleOf="3", + pattern="4", + maxLength=1, + minLength=2, + maxItems=3, + minItems=4, + exclusiveMaximum=true, + exclusiveMinimum=true, + uniqueItems=true, + required=true, + skipIfEmpty=true, + description={"b1","b2"}, + _default={"c1","c2"}, + items=@Items($ref="d1"), + _enum="e1,e2,e3", + example="f1", + api="{g1:true}" + ) String x + ) { + + } + } + + @Test + public void a03_basic_onParameter() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, A03.class.getMethod("a", String.class), 0).noValidate(true).build(); + assertEquals("x", s.getName()); + assertEquals(HttpPartSchema.Type.NUMBER, s.getType()); + assertEquals(HttpPartSchema.Format.INT32, s.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.CSV, s.getCollectionFormat()); + assertEquals(1, s.getMaximum()); + assertEquals(2, s.getMinimum()); + assertEquals(3, s.getMultipleOf()); + assertEquals("4", s.getPattern().pattern()); + assertEquals(1, s.getMaxLength().longValue()); + assertEquals(2, s.getMinLength().longValue()); + assertEquals(3, s.getMaxItems().longValue()); + assertEquals(4, s.getMinItems().longValue()); + assertTrue(s.getExclusiveMaximum()); + assertTrue(s.getExclusiveMinimum()); + assertTrue(s.getUniqueItems()); + assertTrue(s.getRequired()); + assertTrue(s.getSkipIfEmpty()); + assertObjectEquals("['e1','e2','e3']", s.getEnum()); + assertEquals("c1\nc2", s.getDefault()); + assertObjectEquals("{collectionFormat:'csv','default':'c1\\nc2',description:'b1\\nb2','enum':['e1','e2','e3'],example:'f1',exclusiveMaximum:true,exclusiveMinimum:true,format:'int32',items:{'$ref':'d1'},maximum:'1',maxItems:3,maxLength:1,minimum:'2',minItems:4,minLength:2,multipleOf:'3',pattern:'4',required:true,type:'number',uniqueItems:true,_value:'{g1:true}'}", s.getApi()); + } + + public static class A04 { + public void a( + @Header( + name="y", + type="integer", + format="int64", + collectionFormat="ssv", + maximum="5", + minimum="6", + multipleOf="7", + pattern="8", + maxLength=5, + minLength=6, + maxItems=7, + minItems=8, + exclusiveMaximum=false, + exclusiveMinimum=false, + uniqueItems=false, + required=false, + skipIfEmpty=false, + description={"b3","b3"}, + _default={"c3","c4"}, + items=@Items($ref="d2"), + _enum="e4,e5,e6", + example="f2", + api="{g2:true}" + ) A01 x + ) { + + } + } + + @Test + public void a04_basic_onParameterAndClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, A04.class.getMethod("a", A01.class), 0).noValidate(true).build(); + assertEquals("y", s.getName()); + assertEquals(HttpPartSchema.Type.INTEGER, s.getType()); + assertEquals(HttpPartSchema.Format.INT64, s.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.SSV, s.getCollectionFormat()); + assertEquals(5, s.getMaximum()); + assertEquals(6, s.getMinimum()); + assertEquals(7, s.getMultipleOf()); + assertEquals("8", s.getPattern().pattern()); + assertEquals(5, s.getMaxLength().longValue()); + assertEquals(6, s.getMinLength().longValue()); + assertEquals(7, s.getMaxItems().longValue()); + assertEquals(8, s.getMinItems().longValue()); + assertNull(s.getExclusiveMaximum()); + assertNull(s.getExclusiveMinimum()); + assertNull(s.getUniqueItems()); + assertNull(s.getRequired()); + assertNull(s.getSkipIfEmpty()); + assertObjectEquals("['e4','e5','e6']", s.getEnum()); + assertEquals("c3\nc4", s.getDefault()); + assertObjectEquals("{collectionFormat:'ssv','default':'c3\\nc4',description:'b3\\nb3','enum':['e4','e5','e6'],example:'f2',format:'int64',items:{'$ref':'d2'},maximum:'5',maxItems:7,maxLength:5,minimum:'6',minItems:8,minLength:6,multipleOf:'7',pattern:'8',type:'integer',_value:'{g2:true}'}", s.getApi()); + } + + @Header( + name="x", + items=@Items( + type="number", + format="int32", + collectionFormat="csv", + maximum="1", + minimum="2", + multipleOf="3", + pattern="4", + maxLength=1, + minLength=2, + maxItems=3, + minItems=4, + exclusiveMaximum=true, + exclusiveMinimum=true, + uniqueItems=true, + _default={"c1","c2"}, + _enum="e1,e2", + items=@SubItems( + type="integer", + format="int64", + collectionFormat="ssv", + maximum="5", + minimum="6", + multipleOf="7", + pattern="8", + maxLength=5, + minLength=6, + maxItems=7, + minItems=8, + exclusiveMaximum=false, + exclusiveMinimum=false, + uniqueItems=false, + _default={"c3","c4"}, + _enum="e3,e4", + items={ + "type:'string',", + "format:'float',", + "collectionFormat:'tsv',", + "maximum:'9',", + "minimum:'10',", + "multipleOf:'11',", + "pattern:'12',", + "maxLength:9,", + "minLength:10,", + "maxItems:11,", + "minItems:12,", + "exclusiveMaximum:true,", + "exclusiveMinimum:true,", + "uniqueItems:true,", + "default:'c5\\nc6',", + "enum:['e5','e6'],", + "items:{", + "type:'array',", + "format:'double',", + "collectionFormat:'pipes',", + "maximum:'13',", + "minimum:'14',", + "multipleOf:'15',", + "pattern:'16',", + "maxLength:13,", + "minLength:14,", + "maxItems:15,", + "minItems:16,", + "exclusiveMaximum:false,", + "exclusiveMinimum:false,", + "uniqueItems:false,", + "default:'c7\\nc8',", + "enum:['e7','e8']", + "}" + } + ) + ) + ) + public static class A05 {} + + @Test + public void a05_basic_nestedItems_onClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, A05.class).noValidate(true).build(); + assertEquals("x", s.getName()); + + HttpPartSchema items = s.getItems(); + assertEquals(HttpPartSchema.Type.NUMBER, items.getType()); + assertEquals(HttpPartSchema.Format.INT32, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.CSV, items.getCollectionFormat()); + assertEquals(1, items.getMaximum()); + assertEquals(2, items.getMinimum()); + assertEquals(3, items.getMultipleOf()); + assertEquals("4", items.getPattern().pattern()); + assertEquals(1, items.getMaxLength().longValue()); + assertEquals(2, items.getMinLength().longValue()); + assertEquals(3, items.getMaxItems().longValue()); + assertEquals(4, items.getMinItems().longValue()); + assertTrue(items.getExclusiveMaximum()); + assertTrue(items.getExclusiveMinimum()); + assertTrue(items.getUniqueItems()); + assertObjectEquals("['e1','e2']", items.getEnum()); + assertEquals("c1\nc2", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.INTEGER, items.getType()); + assertEquals(HttpPartSchema.Format.INT64, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.SSV, items.getCollectionFormat()); + assertEquals(5, items.getMaximum()); + assertEquals(6, items.getMinimum()); + assertEquals(7, items.getMultipleOf()); + assertEquals("8", items.getPattern().pattern()); + assertEquals(5, items.getMaxLength().longValue()); + assertEquals(6, items.getMinLength().longValue()); + assertEquals(7, items.getMaxItems().longValue()); + assertEquals(8, items.getMinItems().longValue()); + assertNull(items.getExclusiveMaximum()); + assertNull(items.getExclusiveMinimum()); + assertNull(items.getUniqueItems()); + assertObjectEquals("['e3','e4']", items.getEnum()); + assertEquals("c3\nc4", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.STRING, items.getType()); + assertEquals(HttpPartSchema.Format.FLOAT, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.TSV, items.getCollectionFormat()); + assertEquals(9, items.getMaximum()); + assertEquals(10, items.getMinimum()); + assertEquals(11, items.getMultipleOf()); + assertEquals("12", items.getPattern().pattern()); + assertEquals(9, items.getMaxLength().longValue()); + assertEquals(10, items.getMinLength().longValue()); + assertEquals(11, items.getMaxItems().longValue()); + assertEquals(12, items.getMinItems().longValue()); + assertTrue(items.getExclusiveMaximum()); + assertTrue(items.getExclusiveMinimum()); + assertTrue(items.getUniqueItems()); + assertObjectEquals("['e5','e6']", items.getEnum()); + assertEquals("c5\nc6", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.ARRAY, items.getType()); + assertEquals(HttpPartSchema.Format.DOUBLE, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.PIPES, items.getCollectionFormat()); + assertEquals(13, items.getMaximum()); + assertEquals(14, items.getMinimum()); + assertEquals(15, items.getMultipleOf()); + assertEquals("16", items.getPattern().pattern()); + assertEquals(13, items.getMaxLength().longValue()); + assertEquals(14, items.getMinLength().longValue()); + assertEquals(15, items.getMaxItems().longValue()); + assertEquals(16, items.getMinItems().longValue()); + assertFalse(items.getExclusiveMaximum()); + assertFalse(items.getExclusiveMinimum()); + assertFalse(items.getUniqueItems()); + assertObjectEquals("['e7','e8']", items.getEnum()); + assertEquals("c7\nc8", items.getDefault()); + + assertObjectEquals( + "{items:{collectionFormat:'csv','default':'c1\\nc2','enum':['e1','e2'],format:'int32',exclusiveMaximum:true,exclusiveMinimum:true,items:{collectionFormat:'ssv','default':'c3\\nc4','enum':['e3','e4'],format:'int64',items:{type:'string',format:'float',collectionFormat:'tsv',maximum:'9',minimum:'10',multipleOf:'11',pattern:'12',maxLength:9,minLength:10,maxItems:11,minItems:12,exclusiveMaximum:true,exclusiveMinimum:true,uniqueItems:true,'default':'c5\\nc6','enum':['e5','e6'],items:{type:' [...] + s.getApi() + ); + } + + //----------------------------------------------------------------------------------------------------------------- + // String input validations. + //----------------------------------------------------------------------------------------------------------------- + + @Header(required=true) + public static class B01 {} + + @Test + public void b01_required() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, B01.class).build(); + s.validateInput("x"); + try { + s.validateInput(null); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("No value specified.", e.getLocalizedMessage()); + } + try { + s.validateInput(""); // Empty headers are never allowed. + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Empty value not allowed.", e.getLocalizedMessage()); + } + } + + @Header(pattern="x.*") + public static class B02a {} + + @Test + public void b02a_pattern() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, B02a.class).build(); + s.validateInput("x"); + s.validateInput("xx"); + try { + s.validateInput("y"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match expected pattern. Must match pattern: x.*", e.getLocalizedMessage()); + } + try { + s.validateInput("yx"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match expected pattern. Must match pattern: x.*", e.getLocalizedMessage()); + } + try { + s.validateInput(""); // Empty headers are never allowed. + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Empty value not allowed.", e.getLocalizedMessage()); + } + } + + @Header(minLength=2, maxLength=3) + public static class B03a {} + + @Test + public void b03a_length() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, B03a.class).build(); + s.validateInput("12"); + s.validateInput("123"); + s.validateInput(null); + try { + s.validateInput("1"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + } + + @Header( + items=@Items( + minLength=2, maxLength=3, + items=@SubItems( + minLength=3, maxLength=4, + items={ + "minLength:4,maxLength:5,", + "items:{minLength:5,maxLength:6}" + } + ) + ) + ) + public static class B03b {} + + @Test + public void b03b_length_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, B03b.class).build(); + + s.getItems().validateInput("12"); + s.getItems().getItems().validateInput("123"); + s.getItems().getItems().getItems().validateInput("1234"); + s.getItems().getItems().getItems().getItems().validateInput("12345"); + + s.getItems().validateInput("123"); + s.getItems().getItems().validateInput("1234"); + s.getItems().getItems().getItems().validateInput("12345"); + s.getItems().getItems().getItems().getItems().validateInput("123456"); + + s.getItems().validateInput(null); + s.getItems().getItems().validateInput(null); + s.getItems().getItems().getItems().validateInput(null); + s.getItems().getItems().getItems().getItems().validateInput(null); + + try { + s.getItems().validateInput("1"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("12"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("123"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("12345"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("123456"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("1234567"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + } + + @Header(_enum="X,Y") + public static class B04a {} + + @Test + public void b04a_enum() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, B04a.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @Header(_enum=" X , Y ") + public static class B04b {} + + @Test + public void b04b_enum() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, B04b.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @Header(_enum="['X','Y']") + public static class B04c {} + + @Test + public void b04c_enum_json() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, B04c.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @Header( + items=@Items( + _enum="['W']", + items=@SubItems( + _enum="['X']", + items={ + "enum:['Y'],", + "items:{enum:['Z']}" + } + ) + ) + ) + public static class B04d {} + + @Test + public void b04d_enum_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, B04d.class).build(); + + s.getItems().validateInput("W"); + s.getItems().getItems().validateInput("X"); + s.getItems().getItems().getItems().validateInput("Y"); + s.getItems().getItems().getItems().getItems().validateInput("Z"); + + try { + s.getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['W']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['Y']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['Z']", e.getLocalizedMessage()); + } + } + + //----------------------------------------------------------------------------------------------------------------- + // Numeric validations + //----------------------------------------------------------------------------------------------------------------- + + @Header(minimum="10", maximum="100") + public static class C01a {} + + @Test + public void c01a_minmax_ints() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, C01a.class).build(); + s.validateOutput(10, BeanContext.DEFAULT); + s.validateOutput(100, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(9, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Header( + items=@Items( + minimum="10", maximum="100", + items=@SubItems( + minimum="100", maximum="1000", + items={ + "minimum:1000,maximum:10000,", + "items:{minimum:10000,maximum:100000}" + } + ) + ) + ) + public static class C01b {} + + @Test + public void c01b_minmax_ints_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, C01b.class).build(); + + s.getItems().validateOutput(10, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + + s.getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(9, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(99, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(999, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(9999, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Header(minimum="10", maximum="100", exclusiveMinimum=true, exclusiveMaximum=true) + public static class C02a {} + + @Test + public void c02a_minmax_exclusive() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, C02a.class).build(); + s.validateOutput(11, BeanContext.DEFAULT); + s.validateOutput(99, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Header( + items=@Items( + minimum="10", maximum="100", exclusiveMinimum=true, exclusiveMaximum=true, + items=@SubItems( + minimum="100", maximum="1000", exclusiveMinimum=true, exclusiveMaximum=true, + items={ + "minimum:1000,maximum:10000,exclusiveMinimum:true,exclusiveMaximum:true,", + "items:{minimum:10000,maximum:100000,exclusiveMinimum:true,exclusiveMaximum:true}" + } + ) + ) + ) + public static class C02b {} + + @Test + public void c02b_minmax_exclusive_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, C02b.class).build(); + + s.getItems().validateOutput(11, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(101, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + + s.getItems().validateOutput(99, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(999, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(9999, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(99999, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Header(minimum="10.1", maximum="100.1") + public static class C03a {} + + @Test + public void c03_minmax_floats() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, C03a.class).build(); + s.validateOutput(10.1f, BeanContext.DEFAULT); + s.validateOutput(100.1f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Header( + items=@Items( + minimum="10.1", maximum="100.1", + items=@SubItems( + minimum="100.1", maximum="1000.1", + items={ + "minimum:1000.1,maximum:10000.1,", + "items:{minimum:10000.1,maximum:100000.1}" + } + ) + ) + ) + public static class C03b {} + + @Test + public void c03b_minmax_floats_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, C03b.class).build(); + + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + + s.getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000.1f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Header(minimum="10.1", maximum="100.1", exclusiveMinimum=true, exclusiveMaximum=true) + public static class C04a {} + + @Test + public void c04a_minmax_floats_exclusive() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, C04a.class).build(); + s.validateOutput(10.2f, BeanContext.DEFAULT); + s.validateOutput(100f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Header( + items=@Items( + minimum="10.1", maximum="100.1", exclusiveMinimum=true, exclusiveMaximum=true, + items=@SubItems( + minimum="100.1", maximum="1000.1", exclusiveMinimum=true, exclusiveMaximum=true, + items={ + "minimum:1000.1,maximum:10000.1,exclusiveMinimum:true,exclusiveMaximum:true,", + "items:{minimum:10000.1,maximum:100000.1,exclusiveMinimum:true,exclusiveMaximum:true}" + } + ) + ) + ) + public static class C04b {} + + @Test + public void c04b_minmax_floats_exclusive_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, C04b.class).build(); + + s.getItems().validateOutput(10.2f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + + s.getItems().validateOutput(100f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Header(multipleOf="10") + public static class C05a {} + + @Test + public void c05a_multipleOf() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, C05a.class).build(); + s.validateOutput(0, BeanContext.DEFAULT); + s.validateOutput(10, BeanContext.DEFAULT); + s.validateOutput(20, BeanContext.DEFAULT); + s.validateOutput(10f, BeanContext.DEFAULT); + s.validateOutput(20f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(11, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @Header( + items=@Items( + multipleOf="10", + items=@SubItems( + multipleOf="100", + items={ + "multipleOf:1000,", + "items:{multipleOf:10000}" + } + ) + ) + ) + public static class C05b {} + + @Test + public void c05b_multipleOf_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, C05b.class).build(); + + s.getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + + s.getItems().validateOutput(10, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + + s.getItems().validateOutput(20, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000, BeanContext.DEFAULT); + + s.getItems().validateOutput(10f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + + s.getItems().validateOutput(20f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(11, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @Header(multipleOf="10.1") + public static class C06a {} + + @Test + public void c06a_multipleOf_floats() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, C06a.class).build(); + s.validateOutput(0, BeanContext.DEFAULT); + s.validateOutput(10.1f, BeanContext.DEFAULT); + s.validateOutput(20.2f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @Header( + items=@Items( + multipleOf="10.1", + items=@SubItems( + multipleOf="100.1", + items={ + "multipleOf:1000.1,", + "items:{multipleOf:10000.1}" + } + ) + ) + ) + public static class C06b {} + + @Test + public void c06b_multipleOf_floats_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, C06b.class).build(); + + s.getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + + s.getItems().validateOutput(20.2f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000.2f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + //----------------------------------------------------------------------------------------------------------------- + // Collections/Array validations + //----------------------------------------------------------------------------------------------------------------- + + @Header( + items=@Items( + uniqueItems=true, + items=@SubItems( + uniqueItems=true, + items={ + "uniqueItems:true,", + "items:{uniqueItems:true}" + } + ) + ) + + ) + public static class D01 {} + + @Test + public void d01a_uniqueItems_arrays() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, D01.class).build(); + + String[] good = split("a,b"), bad = split("a,a"); + + s.getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().validateOutput(null, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + } + + @Test + public void d01b_uniqueItems_collections() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, D01.class).build(); + + AList + good = new AList().appendAll(split("a,b")), + bad = new AList().appendAll(split("a,a")); + + s.getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().validateOutput(null, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + } + + @Header( + items=@Items( + minItems=1, maxItems=2, + items=@SubItems( + minItems=2, maxItems=3, + items={ + "minItems:3,maxItems:4,", + "items:{minItems:4,maxItems:5}" + } + ) + ) + + ) + public static class D02 {} + + @Test + public void d02a_minMaxItems_arrays() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Header.class, D02.class).build(); + + s.getItems().validateOutput(split("1"), BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + + s.getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4,5"), BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(new String[0], BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(split("1"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(split("1,2,3,4,5"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4,5,6"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + } +} \ No newline at end of file diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Path.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Path.java new file mode 100644 index 0000000..f88f8ee --- /dev/null +++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Path.java @@ -0,0 +1,1332 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.httppart; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.apache.juneau.testutils.TestUtils.*; +import static org.apache.juneau.internal.StringUtils.*; + +import org.apache.juneau.*; +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.utils.*; +import org.junit.*; + +public class HttpPartSchemaTest_Path { + + //----------------------------------------------------------------------------------------------------------------- + // Basic test + //----------------------------------------------------------------------------------------------------------------- + @Test + public void testBasic() throws Exception { + HttpPartSchema.create().build(); + } + + //----------------------------------------------------------------------------------------------------------------- + // @Path + //----------------------------------------------------------------------------------------------------------------- + + @Path("x") + public static class A01 {} + + @Test + public void a01_value() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, A01.class).build(); + assertEquals("x", s.getName()); + assertObjectEquals("{}", s.getApi()); + } + + @Path( + name="x", + type="number", + format="int32", + collectionFormat="csv", + maximum="1", + minimum="2", + multipleOf="3", + pattern="4", + maxLength=1, + minLength=2, + exclusiveMaximum=true, + exclusiveMinimum=true, + description={"b1","b2"}, + items=@Items($ref="d1"), + _enum="e1,e2,e3", + example="f1", + api="{g1:true}" + ) + public static class A02 {} + + @Test + public void a02_basic_onClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, A02.class).noValidate(true).build(); + assertEquals("x", s.getName()); + assertEquals(HttpPartSchema.Type.NUMBER, s.getType()); + assertEquals(HttpPartSchema.Format.INT32, s.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.CSV, s.getCollectionFormat()); + assertEquals(1, s.getMaximum()); + assertEquals(2, s.getMinimum()); + assertEquals(3, s.getMultipleOf()); + assertEquals("4", s.getPattern().pattern()); + assertEquals(1, s.getMaxLength().longValue()); + assertEquals(2, s.getMinLength().longValue()); + assertTrue(s.getExclusiveMaximum()); + assertTrue(s.getExclusiveMinimum()); + assertObjectEquals("['e1','e2','e3']", s.getEnum()); + assertObjectEquals("{collectionFormat:'csv',description:'b1\\nb2','enum':['e1','e2','e3'],example:'f1',exclusiveMaximum:true,exclusiveMinimum:true,format:'int32',items:{'$ref':'d1'},maximum:'1',maxLength:1,minimum:'2',minLength:2,multipleOf:'3',pattern:'4',type:'number',_value:'{g1:true}'}", s.getApi()); + } + + public static class A03 { + public void a( + @Path( + name="x", + type="number", + format="int32", + collectionFormat="csv", + maximum="1", + minimum="2", + multipleOf="3", + pattern="4", + maxLength=1, + minLength=2, + exclusiveMaximum=true, + exclusiveMinimum=true, + description={"b1","b2"}, + items=@Items($ref="d1"), + _enum="e1,e2,e3", + example="f1", + api="{g1:true}" + ) String x + ) { + + } + } + + @Test + public void a03_basic_onParameter() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, A03.class.getMethod("a", String.class), 0).noValidate(true).build(); + assertEquals("x", s.getName()); + assertEquals(HttpPartSchema.Type.NUMBER, s.getType()); + assertEquals(HttpPartSchema.Format.INT32, s.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.CSV, s.getCollectionFormat()); + assertEquals(1, s.getMaximum()); + assertEquals(2, s.getMinimum()); + assertEquals(3, s.getMultipleOf()); + assertEquals("4", s.getPattern().pattern()); + assertEquals(1, s.getMaxLength().longValue()); + assertEquals(2, s.getMinLength().longValue()); + assertTrue(s.getExclusiveMaximum()); + assertTrue(s.getExclusiveMinimum()); + assertObjectEquals("['e1','e2','e3']", s.getEnum()); + assertObjectEquals("{collectionFormat:'csv',description:'b1\\nb2','enum':['e1','e2','e3'],example:'f1',exclusiveMaximum:true,exclusiveMinimum:true,format:'int32',items:{'$ref':'d1'},maximum:'1',maxLength:1,minimum:'2',minLength:2,multipleOf:'3',pattern:'4',type:'number',_value:'{g1:true}'}", s.getApi()); + } + + public static class A04 { + public void a( + @Path( + name="y", + type="integer", + format="int64", + collectionFormat="ssv", + maximum="5", + minimum="6", + multipleOf="7", + pattern="8", + maxLength=5, + minLength=6, + exclusiveMaximum=false, + exclusiveMinimum=false, + description={"b3","b3"}, + items=@Items($ref="d2"), + _enum="e4,e5,e6", + example="f2", + api="{g2:true}" + ) A01 x + ) { + + } + } + + @Test + public void a04_basic_onParameterAndClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, A04.class.getMethod("a", A01.class), 0).noValidate(true).build(); + assertEquals("y", s.getName()); + assertEquals(HttpPartSchema.Type.INTEGER, s.getType()); + assertEquals(HttpPartSchema.Format.INT64, s.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.SSV, s.getCollectionFormat()); + assertEquals(5, s.getMaximum()); + assertEquals(6, s.getMinimum()); + assertEquals(7, s.getMultipleOf()); + assertEquals("8", s.getPattern().pattern()); + assertEquals(5, s.getMaxLength().longValue()); + assertEquals(6, s.getMinLength().longValue()); + assertNull(s.getExclusiveMaximum()); + assertNull(s.getExclusiveMinimum()); + assertObjectEquals("['e4','e5','e6']", s.getEnum()); + assertObjectEquals("{collectionFormat:'ssv',description:'b3\\nb3','enum':['e4','e5','e6'],example:'f2',format:'int64',items:{'$ref':'d2'},maximum:'5',maxLength:5,minimum:'6',minLength:6,multipleOf:'7',pattern:'8',type:'integer',_value:'{g2:true}'}", s.getApi()); + } + + @Path( + name="x", + items=@Items( + type="number", + format="int32", + collectionFormat="csv", + maximum="1", + minimum="2", + multipleOf="3", + pattern="4", + maxLength=1, + minLength=2, + maxItems=3, + minItems=4, + exclusiveMaximum=true, + exclusiveMinimum=true, + uniqueItems=true, + _default={"c1","c2"}, + _enum="e1,e2", + items=@SubItems( + type="integer", + format="int64", + collectionFormat="ssv", + maximum="5", + minimum="6", + multipleOf="7", + pattern="8", + maxLength=5, + minLength=6, + maxItems=7, + minItems=8, + exclusiveMaximum=false, + exclusiveMinimum=false, + uniqueItems=false, + _default={"c3","c4"}, + _enum="e3,e4", + items={ + "type:'string',", + "format:'float',", + "collectionFormat:'tsv',", + "maximum:'9',", + "minimum:'10',", + "multipleOf:'11',", + "pattern:'12',", + "maxLength:9,", + "minLength:10,", + "maxItems:11,", + "minItems:12,", + "exclusiveMaximum:true,", + "exclusiveMinimum:true,", + "uniqueItems:true,", + "default:'c5\\nc6',", + "enum:['e5','e6'],", + "items:{", + "type:'array',", + "format:'double',", + "collectionFormat:'pipes',", + "maximum:'13',", + "minimum:'14',", + "multipleOf:'15',", + "pattern:'16',", + "maxLength:13,", + "minLength:14,", + "maxItems:15,", + "minItems:16,", + "exclusiveMaximum:false,", + "exclusiveMinimum:false,", + "uniqueItems:false,", + "default:'c7\\nc8',", + "enum:['e7','e8']", + "}" + } + ) + ) + ) + public static class A05 {} + + @Test + public void a05_basic_nestedItems_onClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, A05.class).noValidate(true).build(); + assertEquals("x", s.getName()); + + HttpPartSchema items = s.getItems(); + assertEquals(HttpPartSchema.Type.NUMBER, items.getType()); + assertEquals(HttpPartSchema.Format.INT32, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.CSV, items.getCollectionFormat()); + assertEquals(1, items.getMaximum()); + assertEquals(2, items.getMinimum()); + assertEquals(3, items.getMultipleOf()); + assertEquals("4", items.getPattern().pattern()); + assertEquals(1, items.getMaxLength().longValue()); + assertEquals(2, items.getMinLength().longValue()); + assertEquals(3, items.getMaxItems().longValue()); + assertEquals(4, items.getMinItems().longValue()); + assertTrue(items.getExclusiveMaximum()); + assertTrue(items.getExclusiveMinimum()); + assertTrue(items.getUniqueItems()); + assertObjectEquals("['e1','e2']", items.getEnum()); + assertEquals("c1\nc2", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.INTEGER, items.getType()); + assertEquals(HttpPartSchema.Format.INT64, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.SSV, items.getCollectionFormat()); + assertEquals(5, items.getMaximum()); + assertEquals(6, items.getMinimum()); + assertEquals(7, items.getMultipleOf()); + assertEquals("8", items.getPattern().pattern()); + assertEquals(5, items.getMaxLength().longValue()); + assertEquals(6, items.getMinLength().longValue()); + assertEquals(7, items.getMaxItems().longValue()); + assertEquals(8, items.getMinItems().longValue()); + assertNull(items.getExclusiveMaximum()); + assertNull(items.getExclusiveMinimum()); + assertNull(items.getUniqueItems()); + assertObjectEquals("['e3','e4']", items.getEnum()); + assertEquals("c3\nc4", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.STRING, items.getType()); + assertEquals(HttpPartSchema.Format.FLOAT, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.TSV, items.getCollectionFormat()); + assertEquals(9, items.getMaximum()); + assertEquals(10, items.getMinimum()); + assertEquals(11, items.getMultipleOf()); + assertEquals("12", items.getPattern().pattern()); + assertEquals(9, items.getMaxLength().longValue()); + assertEquals(10, items.getMinLength().longValue()); + assertEquals(11, items.getMaxItems().longValue()); + assertEquals(12, items.getMinItems().longValue()); + assertTrue(items.getExclusiveMaximum()); + assertTrue(items.getExclusiveMinimum()); + assertTrue(items.getUniqueItems()); + assertObjectEquals("['e5','e6']", items.getEnum()); + assertEquals("c5\nc6", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.ARRAY, items.getType()); + assertEquals(HttpPartSchema.Format.DOUBLE, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.PIPES, items.getCollectionFormat()); + assertEquals(13, items.getMaximum()); + assertEquals(14, items.getMinimum()); + assertEquals(15, items.getMultipleOf()); + assertEquals("16", items.getPattern().pattern()); + assertEquals(13, items.getMaxLength().longValue()); + assertEquals(14, items.getMinLength().longValue()); + assertEquals(15, items.getMaxItems().longValue()); + assertEquals(16, items.getMinItems().longValue()); + assertFalse(items.getExclusiveMaximum()); + assertFalse(items.getExclusiveMinimum()); + assertFalse(items.getUniqueItems()); + assertObjectEquals("['e7','e8']", items.getEnum()); + assertEquals("c7\nc8", items.getDefault()); + + assertObjectEquals( + "{items:{collectionFormat:'csv','default':'c1\\nc2','enum':['e1','e2'],format:'int32',exclusiveMaximum:true,exclusiveMinimum:true,items:{collectionFormat:'ssv','default':'c3\\nc4','enum':['e3','e4'],format:'int64',items:{type:'string',format:'float',collectionFormat:'tsv',maximum:'9',minimum:'10',multipleOf:'11',pattern:'12',maxLength:9,minLength:10,maxItems:11,minItems:12,exclusiveMaximum:true,exclusiveMinimum:true,uniqueItems:true,'default':'c5\\nc6','enum':['e5','e6'],items:{type:' [...] + s.getApi() + ); + } + + //----------------------------------------------------------------------------------------------------------------- + // String input validations. + //----------------------------------------------------------------------------------------------------------------- + + @Path(pattern="x.*") + public static class B02a {} + + @Test + public void b02a_pattern() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, B02a.class).build(); + s.validateInput("x"); + s.validateInput("xx"); + try { + s.validateInput("y"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match expected pattern. Must match pattern: x.*", e.getLocalizedMessage()); + } + try { + s.validateInput("yx"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match expected pattern. Must match pattern: x.*", e.getLocalizedMessage()); + } + try { + s.validateInput(""); // Empty headers are never allowed. + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Empty value not allowed.", e.getLocalizedMessage()); + } + } + + @Path(minLength=2, maxLength=3) + public static class B03a {} + + @Test + public void b03a_length() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, B03a.class).build(); + s.validateInput("12"); + s.validateInput("123"); + s.validateInput(null); + try { + s.validateInput("1"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + } + + @Path( + items=@Items( + minLength=2, maxLength=3, + items=@SubItems( + minLength=3, maxLength=4, + items={ + "minLength:4,maxLength:5,", + "items:{minLength:5,maxLength:6}" + } + ) + ) + ) + public static class B03b {} + + @Test + public void b03b_length_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, B03b.class).build(); + + s.getItems().validateInput("12"); + s.getItems().getItems().validateInput("123"); + s.getItems().getItems().getItems().validateInput("1234"); + s.getItems().getItems().getItems().getItems().validateInput("12345"); + + s.getItems().validateInput("123"); + s.getItems().getItems().validateInput("1234"); + s.getItems().getItems().getItems().validateInput("12345"); + s.getItems().getItems().getItems().getItems().validateInput("123456"); + + s.getItems().validateInput(null); + s.getItems().getItems().validateInput(null); + s.getItems().getItems().getItems().validateInput(null); + s.getItems().getItems().getItems().getItems().validateInput(null); + + try { + s.getItems().validateInput("1"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("12"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("123"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("12345"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("123456"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("1234567"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + } + + @Path(_enum="X,Y") + public static class B04a {} + + @Test + public void b04a_enum() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, B04a.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @Path(_enum=" X , Y ") + public static class B04b {} + + @Test + public void b04b_enum() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, B04b.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @Path(_enum="['X','Y']") + public static class B04c {} + + @Test + public void b04c_enum_json() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, B04c.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @Path( + items=@Items( + _enum="['W']", + items=@SubItems( + _enum="['X']", + items={ + "enum:['Y'],", + "items:{enum:['Z']}" + } + ) + ) + ) + public static class B04d {} + + @Test + public void b04d_enum_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, B04d.class).build(); + + s.getItems().validateInput("W"); + s.getItems().getItems().validateInput("X"); + s.getItems().getItems().getItems().validateInput("Y"); + s.getItems().getItems().getItems().getItems().validateInput("Z"); + + try { + s.getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['W']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['Y']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['Z']", e.getLocalizedMessage()); + } + } + + //----------------------------------------------------------------------------------------------------------------- + // Numeric validations + //----------------------------------------------------------------------------------------------------------------- + + @Path(minimum="10", maximum="100") + public static class C01a {} + + @Test + public void c01a_minmax_ints() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, C01a.class).build(); + s.validateOutput(10, BeanContext.DEFAULT); + s.validateOutput(100, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(9, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Path( + items=@Items( + minimum="10", maximum="100", + items=@SubItems( + minimum="100", maximum="1000", + items={ + "minimum:1000,maximum:10000,", + "items:{minimum:10000,maximum:100000}" + } + ) + ) + ) + public static class C01b {} + + @Test + public void c01b_minmax_ints_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, C01b.class).build(); + + s.getItems().validateOutput(10, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + + s.getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(9, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(99, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(999, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(9999, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Path(minimum="10", maximum="100", exclusiveMinimum=true, exclusiveMaximum=true) + public static class C02a {} + + @Test + public void c02a_minmax_exclusive() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, C02a.class).build(); + s.validateOutput(11, BeanContext.DEFAULT); + s.validateOutput(99, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Path( + items=@Items( + minimum="10", maximum="100", exclusiveMinimum=true, exclusiveMaximum=true, + items=@SubItems( + minimum="100", maximum="1000", exclusiveMinimum=true, exclusiveMaximum=true, + items={ + "minimum:1000,maximum:10000,exclusiveMinimum:true,exclusiveMaximum:true,", + "items:{minimum:10000,maximum:100000,exclusiveMinimum:true,exclusiveMaximum:true}" + } + ) + ) + ) + public static class C02b {} + + @Test + public void c02b_minmax_exclusive_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, C02b.class).build(); + + s.getItems().validateOutput(11, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(101, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + + s.getItems().validateOutput(99, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(999, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(9999, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(99999, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Path(minimum="10.1", maximum="100.1") + public static class C03a {} + + @Test + public void c03_minmax_floats() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, C03a.class).build(); + s.validateOutput(10.1f, BeanContext.DEFAULT); + s.validateOutput(100.1f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Path( + items=@Items( + minimum="10.1", maximum="100.1", + items=@SubItems( + minimum="100.1", maximum="1000.1", + items={ + "minimum:1000.1,maximum:10000.1,", + "items:{minimum:10000.1,maximum:100000.1}" + } + ) + ) + ) + public static class C03b {} + + @Test + public void c03b_minmax_floats_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, C03b.class).build(); + + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + + s.getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000.1f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Path(minimum="10.1", maximum="100.1", exclusiveMinimum=true, exclusiveMaximum=true) + public static class C04a {} + + @Test + public void c04a_minmax_floats_exclusive() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, C04a.class).build(); + s.validateOutput(10.2f, BeanContext.DEFAULT); + s.validateOutput(100f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Path( + items=@Items( + minimum="10.1", maximum="100.1", exclusiveMinimum=true, exclusiveMaximum=true, + items=@SubItems( + minimum="100.1", maximum="1000.1", exclusiveMinimum=true, exclusiveMaximum=true, + items={ + "minimum:1000.1,maximum:10000.1,exclusiveMinimum:true,exclusiveMaximum:true,", + "items:{minimum:10000.1,maximum:100000.1,exclusiveMinimum:true,exclusiveMaximum:true}" + } + ) + ) + ) + public static class C04b {} + + @Test + public void c04b_minmax_floats_exclusive_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, C04b.class).build(); + + s.getItems().validateOutput(10.2f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + + s.getItems().validateOutput(100f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Path(multipleOf="10") + public static class C05a {} + + @Test + public void c05a_multipleOf() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, C05a.class).build(); + s.validateOutput(0, BeanContext.DEFAULT); + s.validateOutput(10, BeanContext.DEFAULT); + s.validateOutput(20, BeanContext.DEFAULT); + s.validateOutput(10f, BeanContext.DEFAULT); + s.validateOutput(20f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(11, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @Path( + items=@Items( + multipleOf="10", + items=@SubItems( + multipleOf="100", + items={ + "multipleOf:1000,", + "items:{multipleOf:10000}" + } + ) + ) + ) + public static class C05b {} + + @Test + public void c05b_multipleOf_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, C05b.class).build(); + + s.getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + + s.getItems().validateOutput(10, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + + s.getItems().validateOutput(20, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000, BeanContext.DEFAULT); + + s.getItems().validateOutput(10f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + + s.getItems().validateOutput(20f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(11, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @Path(multipleOf="10.1") + public static class C06a {} + + @Test + public void c06a_multipleOf_floats() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, C06a.class).build(); + s.validateOutput(0, BeanContext.DEFAULT); + s.validateOutput(10.1f, BeanContext.DEFAULT); + s.validateOutput(20.2f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @Path( + items=@Items( + multipleOf="10.1", + items=@SubItems( + multipleOf="100.1", + items={ + "multipleOf:1000.1,", + "items:{multipleOf:10000.1}" + } + ) + ) + ) + public static class C06b {} + + @Test + public void c06b_multipleOf_floats_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, C06b.class).build(); + + s.getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + + s.getItems().validateOutput(20.2f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000.2f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + //----------------------------------------------------------------------------------------------------------------- + // Collections/Array validations + //----------------------------------------------------------------------------------------------------------------- + + @Path( + items=@Items( + uniqueItems=true, + items=@SubItems( + uniqueItems=true, + items={ + "uniqueItems:true,", + "items:{uniqueItems:true}" + } + ) + ) + + ) + public static class D01 {} + + @Test + public void d01a_uniqueItems_arrays() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, D01.class).build(); + + String[] good = split("a,b"), bad = split("a,a"); + + s.getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().validateOutput(null, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + } + + @Test + public void d01b_uniqueItems_collections() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, D01.class).build(); + + AList + good = new AList().appendAll(split("a,b")), + bad = new AList().appendAll(split("a,a")); + + s.getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().validateOutput(null, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + } + + @Path( + items=@Items( + minItems=1, maxItems=2, + items=@SubItems( + minItems=2, maxItems=3, + items={ + "minItems:3,maxItems:4,", + "items:{minItems:4,maxItems:5}" + } + ) + ) + + ) + public static class D02 {} + + @Test + public void d02a_minMaxItems_arrays() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Path.class, D02.class).build(); + + s.getItems().validateOutput(split("1"), BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + + s.getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4,5"), BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(new String[0], BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(split("1"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(split("1,2,3,4,5"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4,5,6"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + } +} \ No newline at end of file diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Query.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Query.java new file mode 100644 index 0000000..c8fb7a0 --- /dev/null +++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Query.java @@ -0,0 +1,1419 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.httppart; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.apache.juneau.testutils.TestUtils.*; +import static org.apache.juneau.internal.StringUtils.*; + +import org.apache.juneau.*; +import org.apache.juneau.http.annotation.*; +import org.apache.juneau.utils.*; +import org.junit.*; + +public class HttpPartSchemaTest_Query { + + //----------------------------------------------------------------------------------------------------------------- + // Basic test + //----------------------------------------------------------------------------------------------------------------- + @Test + public void testBasic() throws Exception { + HttpPartSchema.create().build(); + } + + //----------------------------------------------------------------------------------------------------------------- + // @Query + //----------------------------------------------------------------------------------------------------------------- + + @Query("x") + public static class A01 {} + + @Test + public void a01_value() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, A01.class).build(); + assertEquals("x", s.getName()); + assertObjectEquals("{}", s.getApi()); + } + + @Query( + name="x", + type="number", + format="int32", + collectionFormat="csv", + maximum="1", + minimum="2", + multipleOf="3", + pattern="4", + maxLength=1, + minLength=2, + maxItems=3, + minItems=4, + exclusiveMaximum=true, + exclusiveMinimum=true, + uniqueItems=true, + required=true, + skipIfEmpty=true, + description={"b1","b2"}, + _default={"c1","c2"}, + items=@Items($ref="d1"), + _enum="e1,e2,e3", + example="f1", + api="{g1:true}" + ) + public static class A02 {} + + @Test + public void a02_basic_onClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, A02.class).noValidate(true).build(); + assertEquals("x", s.getName()); + assertEquals(HttpPartSchema.Type.NUMBER, s.getType()); + assertEquals(HttpPartSchema.Format.INT32, s.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.CSV, s.getCollectionFormat()); + assertEquals(1, s.getMaximum()); + assertEquals(2, s.getMinimum()); + assertEquals(3, s.getMultipleOf()); + assertEquals("4", s.getPattern().pattern()); + assertEquals(1, s.getMaxLength().longValue()); + assertEquals(2, s.getMinLength().longValue()); + assertEquals(3, s.getMaxItems().longValue()); + assertEquals(4, s.getMinItems().longValue()); + assertTrue(s.getExclusiveMaximum()); + assertTrue(s.getExclusiveMinimum()); + assertTrue(s.getUniqueItems()); + assertTrue(s.getRequired()); + assertTrue(s.getSkipIfEmpty()); + assertObjectEquals("['e1','e2','e3']", s.getEnum()); + assertEquals("c1\nc2", s.getDefault()); + assertObjectEquals("{collectionFormat:'csv','default':'c1\\nc2',description:'b1\\nb2','enum':['e1','e2','e3'],example:'f1',exclusiveMaximum:true,exclusiveMinimum:true,format:'int32',items:{'$ref':'d1'},maximum:'1',maxItems:3,maxLength:1,minimum:'2',minItems:4,minLength:2,multipleOf:'3',pattern:'4',required:true,type:'number',uniqueItems:true,_value:'{g1:true}'}", s.getApi()); + } + + public static class A03 { + public void a( + @Query( + name="x", + type="number", + format="int32", + collectionFormat="csv", + maximum="1", + minimum="2", + multipleOf="3", + pattern="4", + maxLength=1, + minLength=2, + maxItems=3, + minItems=4, + exclusiveMaximum=true, + exclusiveMinimum=true, + uniqueItems=true, + required=true, + skipIfEmpty=true, + description={"b1","b2"}, + _default={"c1","c2"}, + items=@Items($ref="d1"), + _enum="e1,e2,e3", + example="f1", + api="{g1:true}" + ) String x + ) { + + } + } + + @Test + public void a03_basic_onParameter() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, A03.class.getMethod("a", String.class), 0).noValidate(true).build(); + assertEquals("x", s.getName()); + assertEquals(HttpPartSchema.Type.NUMBER, s.getType()); + assertEquals(HttpPartSchema.Format.INT32, s.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.CSV, s.getCollectionFormat()); + assertEquals(1, s.getMaximum()); + assertEquals(2, s.getMinimum()); + assertEquals(3, s.getMultipleOf()); + assertEquals("4", s.getPattern().pattern()); + assertEquals(1, s.getMaxLength().longValue()); + assertEquals(2, s.getMinLength().longValue()); + assertEquals(3, s.getMaxItems().longValue()); + assertEquals(4, s.getMinItems().longValue()); + assertTrue(s.getExclusiveMaximum()); + assertTrue(s.getExclusiveMinimum()); + assertTrue(s.getUniqueItems()); + assertTrue(s.getRequired()); + assertTrue(s.getSkipIfEmpty()); + assertObjectEquals("['e1','e2','e3']", s.getEnum()); + assertEquals("c1\nc2", s.getDefault()); + assertObjectEquals("{collectionFormat:'csv','default':'c1\\nc2',description:'b1\\nb2','enum':['e1','e2','e3'],example:'f1',exclusiveMaximum:true,exclusiveMinimum:true,format:'int32',items:{'$ref':'d1'},maximum:'1',maxItems:3,maxLength:1,minimum:'2',minItems:4,minLength:2,multipleOf:'3',pattern:'4',required:true,type:'number',uniqueItems:true,_value:'{g1:true}'}", s.getApi()); + } + + public static class A04 { + public void a( + @Query( + name="y", + type="integer", + format="int64", + collectionFormat="ssv", + maximum="5", + minimum="6", + multipleOf="7", + pattern="8", + maxLength=5, + minLength=6, + maxItems=7, + minItems=8, + exclusiveMaximum=false, + exclusiveMinimum=false, + uniqueItems=false, + required=false, + skipIfEmpty=false, + description={"b3","b3"}, + _default={"c3","c4"}, + items=@Items($ref="d2"), + _enum="e4,e5,e6", + example="f2", + api="{g2:true}" + ) A01 x + ) { + + } + } + + @Test + public void a04_basic_onParameterAndClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, A04.class.getMethod("a", A01.class), 0).noValidate(true).build(); + assertEquals("y", s.getName()); + assertEquals(HttpPartSchema.Type.INTEGER, s.getType()); + assertEquals(HttpPartSchema.Format.INT64, s.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.SSV, s.getCollectionFormat()); + assertEquals(5, s.getMaximum()); + assertEquals(6, s.getMinimum()); + assertEquals(7, s.getMultipleOf()); + assertEquals("8", s.getPattern().pattern()); + assertEquals(5, s.getMaxLength().longValue()); + assertEquals(6, s.getMinLength().longValue()); + assertEquals(7, s.getMaxItems().longValue()); + assertEquals(8, s.getMinItems().longValue()); + assertNull(s.getExclusiveMaximum()); + assertNull(s.getExclusiveMinimum()); + assertNull(s.getUniqueItems()); + assertNull(s.getRequired()); + assertNull(s.getSkipIfEmpty()); + assertObjectEquals("['e4','e5','e6']", s.getEnum()); + assertEquals("c3\nc4", s.getDefault()); + assertObjectEquals("{collectionFormat:'ssv','default':'c3\\nc4',description:'b3\\nb3','enum':['e4','e5','e6'],example:'f2',format:'int64',items:{'$ref':'d2'},maximum:'5',maxItems:7,maxLength:5,minimum:'6',minItems:8,minLength:6,multipleOf:'7',pattern:'8',type:'integer',_value:'{g2:true}'}", s.getApi()); + } + + @Query( + name="x", + items=@Items( + type="number", + format="int32", + collectionFormat="csv", + maximum="1", + minimum="2", + multipleOf="3", + pattern="4", + maxLength=1, + minLength=2, + maxItems=3, + minItems=4, + exclusiveMaximum=true, + exclusiveMinimum=true, + uniqueItems=true, + _default={"c1","c2"}, + _enum="e1,e2", + items=@SubItems( + type="integer", + format="int64", + collectionFormat="ssv", + maximum="5", + minimum="6", + multipleOf="7", + pattern="8", + maxLength=5, + minLength=6, + maxItems=7, + minItems=8, + exclusiveMaximum=false, + exclusiveMinimum=false, + uniqueItems=false, + _default={"c3","c4"}, + _enum="e3,e4", + items={ + "type:'string',", + "format:'float',", + "collectionFormat:'tsv',", + "maximum:'9',", + "minimum:'10',", + "multipleOf:'11',", + "pattern:'12',", + "maxLength:9,", + "minLength:10,", + "maxItems:11,", + "minItems:12,", + "exclusiveMaximum:true,", + "exclusiveMinimum:true,", + "uniqueItems:true,", + "default:'c5\\nc6',", + "enum:['e5','e6'],", + "items:{", + "type:'array',", + "format:'double',", + "collectionFormat:'pipes',", + "maximum:'13',", + "minimum:'14',", + "multipleOf:'15',", + "pattern:'16',", + "maxLength:13,", + "minLength:14,", + "maxItems:15,", + "minItems:16,", + "exclusiveMaximum:false,", + "exclusiveMinimum:false,", + "uniqueItems:false,", + "default:'c7\\nc8',", + "enum:['e7','e8']", + "}" + } + ) + ) + ) + public static class A05 {} + + @Test + public void a05_basic_nestedItems_onClass() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, A05.class).noValidate(true).build(); + assertEquals("x", s.getName()); + + HttpPartSchema items = s.getItems(); + assertEquals(HttpPartSchema.Type.NUMBER, items.getType()); + assertEquals(HttpPartSchema.Format.INT32, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.CSV, items.getCollectionFormat()); + assertEquals(1, items.getMaximum()); + assertEquals(2, items.getMinimum()); + assertEquals(3, items.getMultipleOf()); + assertEquals("4", items.getPattern().pattern()); + assertEquals(1, items.getMaxLength().longValue()); + assertEquals(2, items.getMinLength().longValue()); + assertEquals(3, items.getMaxItems().longValue()); + assertEquals(4, items.getMinItems().longValue()); + assertTrue(items.getExclusiveMaximum()); + assertTrue(items.getExclusiveMinimum()); + assertTrue(items.getUniqueItems()); + assertObjectEquals("['e1','e2']", items.getEnum()); + assertEquals("c1\nc2", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.INTEGER, items.getType()); + assertEquals(HttpPartSchema.Format.INT64, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.SSV, items.getCollectionFormat()); + assertEquals(5, items.getMaximum()); + assertEquals(6, items.getMinimum()); + assertEquals(7, items.getMultipleOf()); + assertEquals("8", items.getPattern().pattern()); + assertEquals(5, items.getMaxLength().longValue()); + assertEquals(6, items.getMinLength().longValue()); + assertEquals(7, items.getMaxItems().longValue()); + assertEquals(8, items.getMinItems().longValue()); + assertNull(items.getExclusiveMaximum()); + assertNull(items.getExclusiveMinimum()); + assertNull(items.getUniqueItems()); + assertObjectEquals("['e3','e4']", items.getEnum()); + assertEquals("c3\nc4", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.STRING, items.getType()); + assertEquals(HttpPartSchema.Format.FLOAT, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.TSV, items.getCollectionFormat()); + assertEquals(9, items.getMaximum()); + assertEquals(10, items.getMinimum()); + assertEquals(11, items.getMultipleOf()); + assertEquals("12", items.getPattern().pattern()); + assertEquals(9, items.getMaxLength().longValue()); + assertEquals(10, items.getMinLength().longValue()); + assertEquals(11, items.getMaxItems().longValue()); + assertEquals(12, items.getMinItems().longValue()); + assertTrue(items.getExclusiveMaximum()); + assertTrue(items.getExclusiveMinimum()); + assertTrue(items.getUniqueItems()); + assertObjectEquals("['e5','e6']", items.getEnum()); + assertEquals("c5\nc6", items.getDefault()); + + items = items.getItems(); + assertEquals(HttpPartSchema.Type.ARRAY, items.getType()); + assertEquals(HttpPartSchema.Format.DOUBLE, items.getFormat()); + assertEquals(HttpPartSchema.CollectionFormat.PIPES, items.getCollectionFormat()); + assertEquals(13, items.getMaximum()); + assertEquals(14, items.getMinimum()); + assertEquals(15, items.getMultipleOf()); + assertEquals("16", items.getPattern().pattern()); + assertEquals(13, items.getMaxLength().longValue()); + assertEquals(14, items.getMinLength().longValue()); + assertEquals(15, items.getMaxItems().longValue()); + assertEquals(16, items.getMinItems().longValue()); + assertFalse(items.getExclusiveMaximum()); + assertFalse(items.getExclusiveMinimum()); + assertFalse(items.getUniqueItems()); + assertObjectEquals("['e7','e8']", items.getEnum()); + assertEquals("c7\nc8", items.getDefault()); + + assertObjectEquals( + "{items:{collectionFormat:'csv','default':'c1\\nc2','enum':['e1','e2'],format:'int32',exclusiveMaximum:true,exclusiveMinimum:true,items:{collectionFormat:'ssv','default':'c3\\nc4','enum':['e3','e4'],format:'int64',items:{type:'string',format:'float',collectionFormat:'tsv',maximum:'9',minimum:'10',multipleOf:'11',pattern:'12',maxLength:9,minLength:10,maxItems:11,minItems:12,exclusiveMaximum:true,exclusiveMinimum:true,uniqueItems:true,'default':'c5\\nc6','enum':['e5','e6'],items:{type:' [...] + s.getApi() + ); + } + + //----------------------------------------------------------------------------------------------------------------- + // String input validations. + //----------------------------------------------------------------------------------------------------------------- + + @Query(required=true) + public static class B01a {} + + @Test + public void b01a_required() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, B01a.class).build(); + + s.validateInput("x"); + + try { + s.validateInput(null); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("No value specified.", e.getLocalizedMessage()); + } + try { + s.validateInput(""); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Empty value not allowed.", e.getLocalizedMessage()); + } + } + + @Query(allowEmptyValue=true) + public static class B01b {} + + @Test + public void b01b_allowEmptyValue() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, B01b.class).build(); + + s.validateInput(""); + s.validateInput(null); + } + + @Query(required=true,allowEmptyValue=true) + public static class B01c {} + + @Test + public void b01b_required_allowEmptyValue() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, B01c.class).build(); + + s.validateInput(""); + + try { + s.validateInput(null); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("No value specified.", e.getLocalizedMessage()); + } + } + + @Query(pattern="x.*") + public static class B02a {} + + @Test + public void b02a_pattern() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, B02a.class).build(); + s.validateInput("x"); + s.validateInput("xx"); + try { + s.validateInput("y"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match expected pattern. Must match pattern: x.*", e.getLocalizedMessage()); + } + try { + s.validateInput("yx"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match expected pattern. Must match pattern: x.*", e.getLocalizedMessage()); + } + try { + s.validateInput(""); // Empty headers are never allowed. + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Empty value not allowed.", e.getLocalizedMessage()); + } + } + + @Query(minLength=2, maxLength=3) + public static class B03a {} + + @Test + public void b03a_length() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, B03a.class).build(); + s.validateInput("12"); + s.validateInput("123"); + s.validateInput(null); + try { + s.validateInput("1"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + } + + @Query( + items=@Items( + minLength=2, maxLength=3, + items=@SubItems( + minLength=3, maxLength=4, + items={ + "minLength:4,maxLength:5,", + "items:{minLength:5,maxLength:6}" + } + ) + ) + ) + public static class B03b {} + + @Test + public void b03b_length_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, B03b.class).build(); + + s.getItems().validateInput("12"); + s.getItems().getItems().validateInput("123"); + s.getItems().getItems().getItems().validateInput("1234"); + s.getItems().getItems().getItems().getItems().validateInput("12345"); + + s.getItems().validateInput("123"); + s.getItems().getItems().validateInput("1234"); + s.getItems().getItems().getItems().validateInput("12345"); + s.getItems().getItems().getItems().getItems().validateInput("123456"); + + s.getItems().validateInput(null); + s.getItems().getItems().validateInput(null); + s.getItems().getItems().getItems().validateInput(null); + s.getItems().getItems().getItems().getItems().validateInput(null); + + try { + s.getItems().validateInput("1"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("12"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("123"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum length of value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateInput("1234"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("12345"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("123456"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("1234567"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum length of value exceeded.", e.getLocalizedMessage()); + } + } + + @Query(_enum="X,Y") + public static class B04a {} + + @Test + public void b04a_enum() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, B04a.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @Query(_enum=" X , Y ") + public static class B04b {} + + @Test + public void b04b_enum() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, B04b.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @Query(_enum="['X','Y']") + public static class B04c {} + + @Test + public void b04c_enum_json() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, B04c.class).build(); + s.validateInput("X"); + s.validateInput("Y"); + s.validateInput(null); + try { + s.validateInput("Z"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X','Y']", e.getLocalizedMessage()); + } + } + + @Query( + items=@Items( + _enum="['W']", + items=@SubItems( + _enum="['X']", + items={ + "enum:['Y'],", + "items:{enum:['Z']}" + } + ) + ) + ) + public static class B04d {} + + @Test + public void b04d_enum_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, B04d.class).build(); + + s.getItems().validateInput("W"); + s.getItems().getItems().validateInput("X"); + s.getItems().getItems().getItems().validateInput("Y"); + s.getItems().getItems().getItems().getItems().validateInput("Z"); + + try { + s.getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['W']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['X']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['Y']", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateInput("V"); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Value does not match one of the expected values. Must be one of the following: ['Z']", e.getLocalizedMessage()); + } + } + + //----------------------------------------------------------------------------------------------------------------- + // Numeric validations + //----------------------------------------------------------------------------------------------------------------- + + @Query(minimum="10", maximum="100") + public static class C01a {} + + @Test + public void c01a_minmax_ints() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, C01a.class).build(); + s.validateOutput(10, BeanContext.DEFAULT); + s.validateOutput(100, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(9, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Query( + items=@Items( + minimum="10", maximum="100", + items=@SubItems( + minimum="100", maximum="1000", + items={ + "minimum:1000,maximum:10000,", + "items:{minimum:10000,maximum:100000}" + } + ) + ) + ) + public static class C01b {} + + @Test + public void c01b_minmax_ints_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, C01b.class).build(); + + s.getItems().validateOutput(10, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + + s.getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(9, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(99, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(999, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(9999, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Query(minimum="10", maximum="100", exclusiveMinimum=true, exclusiveMaximum=true) + public static class C02a {} + + @Test + public void c02a_minmax_exclusive() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, C02a.class).build(); + s.validateOutput(11, BeanContext.DEFAULT); + s.validateOutput(99, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Query( + items=@Items( + minimum="10", maximum="100", exclusiveMinimum=true, exclusiveMaximum=true, + items=@SubItems( + minimum="100", maximum="1000", exclusiveMinimum=true, exclusiveMaximum=true, + items={ + "minimum:1000,maximum:10000,exclusiveMinimum:true,exclusiveMaximum:true,", + "items:{minimum:10000,maximum:100000,exclusiveMinimum:true,exclusiveMaximum:true}" + } + ) + ) + ) + public static class C02b {} + + @Test + public void c02b_minmax_exclusive_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, C02b.class).build(); + + s.getItems().validateOutput(11, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(101, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + + s.getItems().validateOutput(99, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(999, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(9999, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(99999, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Query(minimum="10.1", maximum="100.1") + public static class C03a {} + + @Test + public void c03_minmax_floats() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, C03a.class).build(); + s.validateOutput(10.1f, BeanContext.DEFAULT); + s.validateOutput(100.1f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Query( + items=@Items( + minimum="10.1", maximum="100.1", + items=@SubItems( + minimum="100.1", maximum="1000.1", + items={ + "minimum:1000.1,maximum:10000.1,", + "items:{minimum:10000.1,maximum:100000.1}" + } + ) + ) + ) + public static class C03b {} + + @Test + public void c03b_minmax_floats_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, C03b.class).build(); + + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + + s.getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000.1f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Query(minimum="10.1", maximum="100.1", exclusiveMinimum=true, exclusiveMaximum=true) + public static class C04a {} + + @Test + public void c04a_minmax_floats_exclusive() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, C04a.class).build(); + s.validateOutput(10.2f, BeanContext.DEFAULT); + s.validateOutput(100f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Query( + items=@Items( + minimum="10.1", maximum="100.1", exclusiveMinimum=true, exclusiveMaximum=true, + items=@SubItems( + minimum="100.1", maximum="1000.1", exclusiveMinimum=true, exclusiveMaximum=true, + items={ + "minimum:1000.1,maximum:10000.1,exclusiveMinimum:true,exclusiveMaximum:true,", + "items:{minimum:10000.1,maximum:100000.1,exclusiveMinimum:true,exclusiveMaximum:true}" + } + ) + ) + ) + public static class C04b {} + + @Test + public void c04b_minmax_floats_exclusive_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, C04b.class).build(); + + s.getItems().validateOutput(10.2f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + + s.getItems().validateOutput(100f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(100000f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum value not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(100.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(100000.1f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum value exceeded.", e.getLocalizedMessage()); + } + } + + @Query(multipleOf="10") + public static class C05a {} + + @Test + public void c05a_multipleOf() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, C05a.class).build(); + s.validateOutput(0, BeanContext.DEFAULT); + s.validateOutput(10, BeanContext.DEFAULT); + s.validateOutput(20, BeanContext.DEFAULT); + s.validateOutput(10f, BeanContext.DEFAULT); + s.validateOutput(20f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(11, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @Query( + items=@Items( + multipleOf="10", + items=@SubItems( + multipleOf="100", + items={ + "multipleOf:1000,", + "items:{multipleOf:10000}" + } + ) + ) + ) + public static class C05b {} + + @Test + public void c05b_multipleOf_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, C05b.class).build(); + + s.getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + + s.getItems().validateOutput(10, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000, BeanContext.DEFAULT); + + s.getItems().validateOutput(20, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000, BeanContext.DEFAULT); + + s.getItems().validateOutput(10f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000f, BeanContext.DEFAULT); + + s.getItems().validateOutput(20f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(11, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(101, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10001, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @Query(multipleOf="10.1") + public static class C06a {} + + @Test + public void c06a_multipleOf_floats() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, C06a.class).build(); + s.validateOutput(0, BeanContext.DEFAULT); + s.validateOutput(10.1f, BeanContext.DEFAULT); + s.validateOutput(20.2f, BeanContext.DEFAULT); + s.validateOutput(null, BeanContext.DEFAULT); + try { + s.validateOutput(10.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + @Query( + items=@Items( + multipleOf="10.1", + items=@SubItems( + multipleOf="100.1", + items={ + "multipleOf:1000.1,", + "items:{multipleOf:10000.1}" + } + ) + ) + ) + public static class C06b {} + + @Test + public void c06b_multipleOf_floats_items() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, C06b.class).build(); + + s.getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(0, BeanContext.DEFAULT); + + s.getItems().validateOutput(10.1f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(100.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(1000.1f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(10000.1f, BeanContext.DEFAULT); + + s.getItems().validateOutput(20.2f, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(200.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(2000.2f, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(20000.2f, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(10.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(100.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(1000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(10000.2f, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Multiple-of not met.", e.getLocalizedMessage()); + } + } + + //----------------------------------------------------------------------------------------------------------------- + // Collections/Array validations + //----------------------------------------------------------------------------------------------------------------- + + @Query( + items=@Items( + uniqueItems=true, + items=@SubItems( + uniqueItems=true, + items={ + "uniqueItems:true,", + "items:{uniqueItems:true}" + } + ) + ) + + ) + public static class D01 {} + + @Test + public void d01a_uniqueItems_arrays() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, D01.class).build(); + + String[] good = split("a,b"), bad = split("a,a"); + + s.getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().validateOutput(null, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + } + + @Test + public void d01b_uniqueItems_collections() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, D01.class).build(); + + AList + good = new AList().appendAll(split("a,b")), + bad = new AList().appendAll(split("a,a")); + + s.getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(good, BeanContext.DEFAULT); + s.getItems().validateOutput(null, BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(bad, BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Duplicate items not allowed.", e.getLocalizedMessage()); + } + } + + @Query( + items=@Items( + minItems=1, maxItems=2, + items=@SubItems( + minItems=2, maxItems=3, + items={ + "minItems:3,maxItems:4,", + "items:{minItems:4,maxItems:5}" + } + ) + ) + + ) + public static class D02 {} + + @Test + public void d02a_minMaxItems_arrays() throws Exception { + HttpPartSchema s = HttpPartSchema.create().apply(Query.class, D02.class).build(); + + s.getItems().validateOutput(split("1"), BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + + s.getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + s.getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4,5"), BeanContext.DEFAULT); + + try { + s.getItems().validateOutput(new String[0], BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(split("1"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(split("1,2"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Minimum number of items not met.", e.getLocalizedMessage()); + } + + try { + s.getItems().validateOutput(split("1,2,3"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().validateOutput(split("1,2,3,4"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().validateOutput(split("1,2,3,4,5"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + try { + s.getItems().getItems().getItems().getItems().validateOutput(split("1,2,3,4,5,6"), BeanContext.DEFAULT); + fail(); + } catch (SchemaValidationParseException e) { + assertEquals("Maximum number of items exceeded.", e.getLocalizedMessage()); + } + } +} \ No newline at end of file diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/testutils/TestUtils.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/testutils/TestUtils.java index abdfced..5aff11f 100644 --- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/testutils/TestUtils.java +++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/testutils/TestUtils.java @@ -382,6 +382,8 @@ public class TestUtils { * Assert that the object equals the specified string after running it through ws.toString(). */ public static final void assertObjectEquals(String s, Object o, WriterSerializer ws) { + if ("xxx".equals(s)) + System.err.println(ws.toString(o).replaceAll("\\\\", "\\\\\\\\")); Assert.assertEquals(s, ws.toString(o)); } diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/AnnotationUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java similarity index 76% copy from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/AnnotationUtils.java copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java index 625a258..c09d782 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/AnnotationUtils.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java @@ -10,13 +10,16 @@ // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * // * specific language governing permissions and limitations under the License. * // *************************************************************************************************************************** -package org.apache.juneau.rest.util; +package org.apache.juneau.http.annotation; import static org.apache.juneau.internal.StringUtils.*; +import java.util.*; + import org.apache.juneau.*; -import org.apache.juneau.rest.annotation.*; -import org.apache.juneau.rest.exception.*; +import org.apache.juneau.internal.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.utils.*; /** * Various reusable utility methods when working with annotations. @@ -45,12 +48,14 @@ public class AnnotationUtils { return om; om = newMap(om); return om - .appendSkipEmpty("_value", joinnl(a.value())) .appendSkipEmpty("description", joinnl(a.description())) - .appendSkipFalse("required", a.required()) .appendSkipEmpty("example", joinnl(a.example())) .appendSkipEmpty("examples", joinnl(a.examples())) - .appendSkipEmpty("schema", merge(om.getObjectMap("schema"), a.schema())); + .appendSkipFalse("required", a.required()) + .appendSkipEmpty("schema", merge(om.getObjectMap("schema"), a.schema())) + .appendSkipEmpty("_value", joinnl(a.value())) + .appendSkipEmpty("_value", joinnl(a.api())) + ; } /** @@ -65,9 +70,10 @@ public class AnnotationUtils { return om; om = newMap(om); return om - .appendSkipEmpty("_value", joinnl(a.value())) .appendSkipEmpty("description", joinnl(a.description())) - .appendSkipEmpty("url", a.url()); + .appendSkipEmpty("url", a.url()) + .appendSkipEmpty("_value", joinnl(a.value())) + ; } /** @@ -81,41 +87,41 @@ public class AnnotationUtils { if (empty(a)) return om; om = newMap(om); - a._enum(); return om - .appendSkipEmpty("_value", joinnl(a.value())) - .appendSkipEmpty("$ref", a.$ref()) - .appendSkipEmpty("format", a.format()) - .appendSkipEmpty("title", a.title()) - .appendSkipEmpty("description", joinnl(a.description())) + .appendSkipEmpty("additionalProperties", toObjectMap(a.additionalProperties())) + .appendSkipEmpty("allOf", joinnl(a.allOf())) .appendSkipEmpty("default", joinnl(a._default())) - .appendSkipEmpty("multipleOf", a.multipleOf()) - .appendSkipEmpty("maximum", a.maximum()) + .appendSkipEmpty("discriminator", a.discriminator()) + .appendSkipEmpty("description", joinnl(a.description())) + .appendSkipEmpty("enum", toSet(a._enum())) + .appendSkipEmpty("example", joinnl(a.example())) + .appendSkipEmpty("examples", joinnl(a.examples())) .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) - .appendSkipEmpty("minimum", a.minimum()) .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) + .appendSkipEmpty("externalDocs", merge(om.getObjectMap("externalDocs"), a.externalDocs())) + .appendSkipEmpty("format", a.format()) + .appendSkipEmpty("ignore", a.ignore() ? "true" : null) + .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) + .appendSkipEmpty("maximum", a.maximum()) + .appendSkipMinusOne("maxItems", a.maxItems()) .appendSkipMinusOne("maxLength", a.maxLength()) + .appendSkipMinusOne("maxProperties", a.maxProperties()) + .appendSkipEmpty("minimum", a.minimum()) + .appendSkipMinusOne("minItems", a.minItems()) .appendSkipMinusOne("minLength", a.minLength()) + .appendSkipMinusOne("minProperties", a.minProperties()) + .appendSkipEmpty("multipleOf", a.multipleOf()) .appendSkipEmpty("pattern", a.pattern()) - .appendSkipMinusOne("maxItems", a.maxItems()) - .appendSkipMinusOne("minItems", a.minItems()) - .appendSkipFalse("uniqueItems", a.uniqueItems()) - .appendSkipEmpty("maxProperties", a.maxProperties()) - .appendSkipEmpty("minProperties", a.minProperties()) + .appendSkipEmpty("properties", toObjectMap(a.properties())) + .appendSkipFalse("readOnly", a.readOnly()) .appendSkipFalse("required", a.required()) - .appendSkipEmpty("enum", joinnl(a._enum())) + .appendSkipEmpty("title", a.title()) .appendSkipEmpty("type", a.type()) - .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) - .appendSkipEmpty("allOf", joinnl(a.allOf())) - .appendSkipEmpty("properties", joinnl(a.properties())) - .appendSkipEmpty("additionalProperties", joinnl(a.additionalProperties())) - .appendSkipEmpty("discriminator", a.discriminator()) - .appendSkipFalse("readOnly", a.readOnly()) + .appendSkipFalse("uniqueItems", a.uniqueItems()) .appendSkipEmpty("xml", joinnl(a.xml())) - .appendSkipEmpty("externalDocs", merge(om.getObjectMap("externalDocs"), a.externalDocs())) - .appendSkipEmpty("example", joinnl(a.example())) - .appendSkipEmpty("examples", joinnl(a.examples())) - .appendSkipEmpty("ignore", a.ignore() ? "true" : null); + .appendSkipEmpty("_value", joinnl(a.value())) + .appendSkipEmpty("$ref", a.$ref()) + ; } /** @@ -130,12 +136,13 @@ public class AnnotationUtils { return om; om = newMap(om); return om - .appendSkipEmpty("_value", joinnl(a.api())) .appendSkipEmpty("description", joinnl(a.description())) .appendSkipEmpty("example", joinnl(a.example())) .appendSkipEmpty("examples", joinnl(a.examples())) + .appendSkipEmpty("headers", merge(om.getObjectMap("headers"), a.headers())) .appendSkipEmpty("schema", merge(om.getObjectMap("schema"), a.schema())) - .appendSkipEmpty("headers", merge(om.getObjectMap("headers"), a.headers())); + .appendSkipEmpty("_value", joinnl(a.api())) + ; } /** @@ -152,7 +159,7 @@ public class AnnotationUtils { for (ResponseHeader aa : a) { String name = firstNonEmpty(aa.name(), aa.value()); if (isEmpty(name)) - throw new InternalServerError("@ResponseHeader used without name or value."); + throw new RuntimeException("@ResponseHeader used without name or value."); om.getObjectMap(name, true).putAll(merge(null, aa)); } return om; @@ -170,26 +177,26 @@ public class AnnotationUtils { return om; om = newMap(om); return om - .appendSkipEmpty("_value", joinnl(a.value())) - .appendSkipEmpty("type", a.type()) - .appendSkipEmpty("format", a.format()) .appendSkipEmpty("collectionFormat", a.collectionFormat()) - .appendSkipEmpty("pattern", a.pattern()) - .appendSkipEmpty("$ref", a.$ref()) + .appendSkipEmpty("default", joinnl(a._default())) + .appendSkipEmpty("enum", toSet(a._enum())) + .appendSkipEmpty("format", a.format()) + .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) + .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) + .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) .appendSkipEmpty("maximum", a.maximum()) - .appendSkipEmpty("minimum", a.minimum()) - .appendSkipEmpty("multipleOf", a.multipleOf()) - .appendSkipMinusOne("maxLength", a.maxLength()) - .appendSkipMinusOne("minLength", a.minLength()) .appendSkipMinusOne("maxItems", a.maxItems()) + .appendSkipMinusOne("maxLength", a.maxLength()) + .appendSkipEmpty("minimum", a.minimum()) .appendSkipMinusOne("minItems", a.minItems()) - .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) - .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) + .appendSkipMinusOne("minLength", a.minLength()) + .appendSkipEmpty("multipleOf", a.multipleOf()) + .appendSkipEmpty("pattern", a.pattern()) .appendSkipFalse("uniqueItems", a.uniqueItems()) - .appendSkipEmpty("default", joinnl(a._default())) - .appendSkipEmpty("enum", joinnl(a._enum())) - .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) - ; + .appendSkipEmpty("type", a.type()) + .appendSkipEmpty("$ref", a.$ref()) + .appendSkipEmpty("_value", joinnl(a.value())) + ; } /** @@ -204,26 +211,26 @@ public class AnnotationUtils { return om; om = newMap(om); return om - .appendSkipEmpty("_value", joinnl(a.value())) - .appendSkipEmpty("type", a.type()) - .appendSkipEmpty("format", a.format()) .appendSkipEmpty("collectionFormat", a.collectionFormat()) - .appendSkipEmpty("pattern", a.pattern()) - .appendSkipEmpty("$ref", a.$ref()) + .appendSkipEmpty("default", joinnl(a._default())) + .appendSkipEmpty("enum", toSet(a._enum())) + .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) + .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) + .appendSkipEmpty("format", a.format()) + .appendSkipEmpty("items", toObjectMap(a.items())) .appendSkipEmpty("maximum", a.maximum()) - .appendSkipEmpty("minimum", a.minimum()) - .appendSkipEmpty("multipleOf", a.multipleOf()) - .appendSkipMinusOne("maxLength", a.maxLength()) - .appendSkipMinusOne("minLength", a.minLength()) .appendSkipMinusOne("maxItems", a.maxItems()) + .appendSkipMinusOne("maxLength", a.maxLength()) + .appendSkipEmpty("minimum", a.minimum()) .appendSkipMinusOne("minItems", a.minItems()) - .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) - .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) + .appendSkipMinusOne("minLength", a.minLength()) + .appendSkipEmpty("multipleOf", a.multipleOf()) + .appendSkipEmpty("pattern", a.pattern()) + .appendSkipEmpty("type", a.type()) .appendSkipFalse("uniqueItems", a.uniqueItems()) - .appendSkipEmpty("default", joinnl(a._default())) - .appendSkipEmpty("enum", joinnl(a._enum())) - .appendSkipEmpty("items", joinnl(a.items())) - ; + .appendSkipEmpty("$ref", a.$ref()) + .appendSkipEmpty("_value", joinnl(a.value())) + ; } /** @@ -238,27 +245,27 @@ public class AnnotationUtils { return om; om = newMap(om); return om - .appendSkipEmpty("_value", joinnl(a.api())) - .appendSkipEmpty("$ref", a.$ref()) + .appendSkipEmpty("collectionFormat", a.collectionFormat()) + .appendSkipEmpty("default", joinnl(a._default())) .appendSkipEmpty("description", joinnl(a.description())) - .appendSkipEmpty("type", a.type()) + .appendSkipEmpty("enum", toSet(a._enum())) + .appendSkipEmpty("example", joinnl(a.example())) + .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) + .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) .appendSkipEmpty("format", a.format()) - .appendSkipEmpty("collectionFormat", a.collectionFormat()) + .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) .appendSkipEmpty("maximum", a.maximum()) - .appendSkipEmpty("minimum", a.minimum()) - .appendSkipEmpty("multipleOf", a.multipleOf()) .appendSkipMinusOne("maxLength", a.maxLength()) - .appendSkipMinusOne("minLength", a.minLength()) .appendSkipMinusOne("maxItems", a.maxItems()) + .appendSkipEmpty("minimum", a.minimum()) + .appendSkipMinusOne("minLength", a.minLength()) .appendSkipMinusOne("minItems", a.minItems()) - .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) - .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) + .appendSkipEmpty("multipleOf", a.multipleOf()) .appendSkipFalse("uniqueItems", a.uniqueItems()) - .appendSkipEmpty("default", joinnl(a._default())) - .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) - .appendSkipEmpty("default", joinnl(a._default())) - .appendSkipEmpty("enum", joinnl(a._enum())) - .appendSkipEmpty("example", joinnl(a.example())); + .appendSkipEmpty("type", a.type()) + .appendSkipEmpty("$ref", a.$ref()) + .appendSkipEmpty("_value", joinnl(a.api())) + ; } /** @@ -289,22 +296,23 @@ public class AnnotationUtils { return om; om = newMap(om); return om - .appendSkipEmpty("_value", joinnl(a.api())) + .appendSkipEmpty("collectionFormat", a.collectionFormat()) .appendSkipEmpty("description", joinnl(a.description())) - .appendSkipEmpty("type", a.type()) - .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) + .appendSkipEmpty("enum", toSet(a._enum())) + .appendSkipEmpty("example", joinnl(a.example())) + .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) + .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) .appendSkipEmpty("format", a.format()) - .appendSkipEmpty("pattern", a.pattern()) - .appendSkipEmpty("collectionFormat", a.collectionFormat()) + .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) .appendSkipEmpty("maximum", a.maximum()) - .appendSkipEmpty("minimum", a.minimum()) - .appendSkipEmpty("multipleOf", a.multipleOf()) .appendSkipMinusOne("maxLength", a.maxLength()) + .appendSkipEmpty("minimum", a.minimum()) .appendSkipMinusOne("minLength", a.minLength()) - .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) - .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) - .appendSkipEmpty("enum", joinnl(a._enum())) - .appendSkipEmpty("example", joinnl(a.example())); + .appendSkipEmpty("multipleOf", a.multipleOf()) + .appendSkipEmpty("pattern", a.pattern()) + .appendSkipEmpty("type", a.type()) + .appendSkipEmpty("_value", joinnl(a.api())) + ; } /** @@ -319,30 +327,31 @@ public class AnnotationUtils { return om; om = newMap(om); return om - .appendSkipEmpty("_value", joinnl(a.api())) + .appendSkipFalse("allowEmptyValue", a.allowEmptyValue()) + .appendSkipEmpty("collectionFormat", a.collectionFormat()) + .appendSkipEmpty("default", joinnl(a._default())) .appendSkipEmpty("description", joinnl(a.description())) - .appendSkipFalse("required", a.required()) - .appendSkipEmpty("type", a.type()) + .appendSkipEmpty("enum", toSet(a._enum())) + .appendSkipEmpty("example", joinnl(a.example())) + .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) + .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) .appendSkipEmpty("format", a.format()) - .appendSkipEmpty("pattern", a.pattern()) - .appendSkipEmpty("collectionFormat", a.collectionFormat()) + .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) .appendSkipEmpty("maximum", a.maximum()) - .appendSkipEmpty("minimum", a.minimum()) - .appendSkipEmpty("multipleOf", a.multipleOf()) - .appendSkipMinusOne("maxLength", a.maxLength()) - .appendSkipMinusOne("minLength", a.minLength()) .appendSkipMinusOne("maxItems", a.maxItems()) + .appendSkipMinusOne("maxLength", a.maxLength()) + .appendSkipEmpty("minimum", a.minimum()) .appendSkipMinusOne("minItems", a.minItems()) - .appendSkipFalse("allowEmptyValue", a.allowEmptyValue()) - .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) - .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) + .appendSkipMinusOne("minLength", a.minLength()) + .appendSkipEmpty("multipleOf", a.multipleOf()) + .appendSkipEmpty("pattern", a.pattern()) + .appendSkipFalse("required", a.required()) + .appendSkipEmpty("type", a.type()) .appendSkipFalse("uniqueItems", a.uniqueItems()) - .appendSkipEmpty("default", joinnl(a._default())) - .appendSkipEmpty("enum", joinnl(a._enum())) - .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) - .appendSkipEmpty("example", joinnl(a.example())); + .appendSkipEmpty("_value", joinnl(a.api())) + ; } - + /** * Merges the contents of the specified annotation into the specified map. * @@ -355,27 +364,28 @@ public class AnnotationUtils { return om; om = newMap(om); return om - .appendSkipEmpty("_value", joinnl(a.api())) + .appendSkipEmpty("collectionFormat", a.collectionFormat()) + .appendSkipEmpty("default", joinnl(a._default())) .appendSkipEmpty("description", joinnl(a.description())) - .appendSkipFalse("required", a.required()) - .appendSkipEmpty("type", a.type()) + .appendSkipEmpty("enum", toSet(a._enum())) + .appendSkipEmpty("example", joinnl(a.example())) + .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) + .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) .appendSkipEmpty("format", a.format()) - .appendSkipEmpty("pattern", a.pattern()) - .appendSkipEmpty("collectionFormat", a.collectionFormat()) + .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) .appendSkipEmpty("maximum", a.maximum()) - .appendSkipEmpty("minimum", a.minimum()) - .appendSkipEmpty("multipleOf", a.multipleOf()) - .appendSkipMinusOne("maxLength", a.maxLength()) - .appendSkipMinusOne("minLength", a.minLength()) .appendSkipMinusOne("maxItems", a.maxItems()) + .appendSkipMinusOne("maxLength", a.maxLength()) + .appendSkipEmpty("minimum", a.minimum()) .appendSkipMinusOne("minItems", a.minItems()) - .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) - .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) + .appendSkipMinusOne("minLength", a.minLength()) + .appendSkipEmpty("multipleOf", a.multipleOf()) + .appendSkipEmpty("pattern", a.pattern()) + .appendSkipFalse("required", a.required()) + .appendSkipEmpty("type", a.type()) .appendSkipFalse("uniqueItems", a.uniqueItems()) - .appendSkipEmpty("default", joinnl(a._default())) - .appendSkipEmpty("enum", joinnl(a._enum())) - .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) - .appendSkipEmpty("example", joinnl(a.example())); + .appendSkipEmpty("_value", joinnl(a.api())) + ; } /** @@ -390,28 +400,29 @@ public class AnnotationUtils { return om; om = newMap(om); return om - .appendSkipEmpty("_value", joinnl(a.api())) + .appendSkipFalse("allowEmptyValue", a.allowEmptyValue()) + .appendSkipEmpty("collectionFormat", a.collectionFormat()) + .appendSkipEmpty("default", joinnl(a._default())) .appendSkipEmpty("description", joinnl(a.description())) - .appendSkipFalse("required", a.required()) - .appendSkipEmpty("type", a.type()) + .appendSkipEmpty("enum", toSet(a._enum())) + .appendSkipEmpty("example", joinnl(a.example())) + .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) + .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) .appendSkipEmpty("format", a.format()) - .appendSkipEmpty("pattern", a.pattern()) - .appendSkipEmpty("collectionFormat", a.collectionFormat()) + .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) .appendSkipEmpty("maximum", a.maximum()) - .appendSkipEmpty("minimum", a.minimum()) - .appendSkipEmpty("multipleOf", a.multipleOf()) - .appendSkipMinusOne("maxLength", a.maxLength()) - .appendSkipMinusOne("minLength", a.minLength()) .appendSkipMinusOne("maxItems", a.maxItems()) + .appendSkipMinusOne("maxLength", a.maxLength()) + .appendSkipEmpty("minimum", a.minimum()) .appendSkipMinusOne("minItems", a.minItems()) - .appendSkipFalse("allowEmptyValue", a.allowEmptyValue()) - .appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum()) - .appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum()) + .appendSkipMinusOne("minLength", a.minLength()) + .appendSkipEmpty("multipleOf", a.multipleOf()) + .appendSkipEmpty("pattern", a.pattern()) + .appendSkipFalse("required", a.required()) + .appendSkipEmpty("type", a.type()) .appendSkipFalse("uniqueItems", a.uniqueItems()) - .appendSkipEmpty("default", joinnl(a._default())) - .appendSkipEmpty("enum", joinnl(a._enum())) - .appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items())) - .appendSkipEmpty("example", joinnl(a.example())); + .appendSkipEmpty("_value", joinnl(a.api())) + ; } //================================================================================================================= @@ -428,10 +439,10 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.description(), a._default(), a.example(), a.api()) - && empty(a.name(), a.value(), a.type(), a.format(), a.pattern(), a.collectionFormat(), a.maximum(), a.minimum(), a.multipleOf()) - && empty(a.allowEmptyValue(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.required(), a.uniqueItems()) - && empty(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()) + allEmpty(a.description(), a._default(), a.example(), a.api()) + && allEmpty(a.name(), a.value(), a.type(), a.format(), a.pattern(), a.collectionFormat(), a.maximum(), a.minimum(), a.multipleOf()) + && allFalse(a.allowEmptyValue(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.required(), a.uniqueItems()) + && allMinusOne(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()) && empty(a.items()); } @@ -445,10 +456,10 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.description(), a._default(), a._enum(), a.example(), a.api()) - && empty(a.name(), a.value(), a.type(), a.format(), a.pattern(), a.collectionFormat(), a.maximum(), a.minimum(), a.multipleOf()) - && empty(a.exclusiveMaximum(), a.exclusiveMinimum(), a.required(), a.uniqueItems()) - && empty(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()) + allEmpty(a.description(), a._default(), a._enum(), a.example(), a.api()) + && allEmpty(a.name(), a.value(), a.type(), a.format(), a.pattern(), a.collectionFormat(), a.maximum(), a.minimum(), a.multipleOf()) + && allFalse(a.exclusiveMaximum(), a.exclusiveMinimum(), a.required(), a.uniqueItems()) + && allMinusOne(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()) && empty(a.items()); } @@ -462,10 +473,10 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.description(), a._default(), a._enum(), a.example(), a.api()) - && empty(a.name(), a.value(), a.type(), a.format(), a.pattern(), a.collectionFormat(), a.maximum(), a.minimum(), a.multipleOf()) - && empty(a.allowEmptyValue(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.required(), a.uniqueItems()) - && empty(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()) + allEmpty(a.description(), a._default(), a._enum(), a.example(), a.api()) + && allEmpty(a.name(), a.value(), a.type(), a.format(), a.pattern(), a.collectionFormat(), a.maximum(), a.minimum(), a.multipleOf()) + && allFalse(a.allowEmptyValue(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.required(), a.uniqueItems()) + && allMinusOne(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()) && empty(a.items()); } @@ -479,7 +490,7 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.description(), a.example(), a.examples(), a.api()) + allEmpty(a.description(), a.example(), a.examples(), a.api()) && a.headers().length == 0 && empty(a.schema()) ; @@ -495,10 +506,10 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.description(), a._default(), a._enum(), a.example(), a.api()) - && empty(a.name(), a.value(), a.type(), a.format(), a.collectionFormat(), a.$ref(), a.maximum(), a.minimum(), a.multipleOf()) - && empty(a.exclusiveMaximum(), a.exclusiveMinimum(), a.uniqueItems()) - && empty(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()) + allEmpty(a.description(), a._default(), a._enum(), a.example(), a.api()) + && allEmpty(a.name(), a.value(), a.type(), a.format(), a.collectionFormat(), a.$ref(), a.maximum(), a.minimum(), a.multipleOf()) + && allFalse(a.exclusiveMaximum(), a.exclusiveMinimum(), a.uniqueItems()) + && allMinusOne(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()) && empty(a.items()); } @@ -512,7 +523,7 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.description(), a.api()); + allEmpty(a.description(), a.api()); } /** @@ -525,10 +536,11 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.value(), a.description(), a._default(), a._enum(), a.allOf(), a.properties(), a.additionalProperties(), a.xml(), a.example(), a.examples()) - && empty(a.$ref(), a.format(), a.title(), a.multipleOf(), a.maximum(), a.minimum(), a.pattern(), a.maxProperties(), a.minProperties(), a.type(), a.discriminator()) - && empty(a.ignore(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.readOnly(), a.required(), a.uniqueItems()) - && empty(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()) + allEmpty(a.value(), a.description(), a._default(), a._enum(), a.allOf(), a.properties(), a.additionalProperties(), a.xml(), a.example(), a.examples()) + && allEmpty(a.$ref(), a.format(), a.title(), a.multipleOf(), a.maximum(), a.minimum(), a.pattern(), a.type(), a.discriminator()) + && allMinusOne(a.maxProperties(), a.minProperties()) + && allFalse(a.ignore(), a.exclusiveMaximum(), a.exclusiveMinimum(), a.readOnly(), a.required(), a.uniqueItems()) + && allMinusOne(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()) && empty(a.items()) && empty(a.externalDocs()); } @@ -543,8 +555,8 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.value(), a.description()) - && empty(a.url()); + allEmpty(a.value(), a.description()) + && allEmpty(a.url()); } /** @@ -557,8 +569,8 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.description(), a.example(), a.examples(), a.value()) - && empty(a.required()) + allEmpty(a.description(), a.example(), a.examples(), a.api(), a.value()) + && allFalse(a.required()) && empty(a.schema()); } @@ -572,8 +584,8 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.value()) - && empty(a.name(), a.url(), a.email()); + allEmpty(a.value()) + && allEmpty(a.name(), a.url(), a.email()); } /** @@ -586,8 +598,8 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.value()) - && empty(a.name(), a.url()); + allEmpty(a.value()) + && allEmpty(a.name(), a.url()); } /** @@ -600,10 +612,10 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.value(), a._default(), a._enum()) - && empty(a.type(), a.format(), a.collectionFormat(), a.pattern(), a.$ref(), a.maximum(), a.minimum(), a.multipleOf()) - && empty(a.exclusiveMaximum(), a.exclusiveMinimum(), a.uniqueItems()) - && empty(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()) + allEmpty(a.value(), a._default(), a._enum()) + && allEmpty(a.type(), a.format(), a.collectionFormat(), a.pattern(), a.$ref(), a.maximum(), a.minimum(), a.multipleOf()) + && allFalse(a.exclusiveMaximum(), a.exclusiveMinimum(), a.uniqueItems()) + && allMinusOne(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()) && empty(a.items()); } @@ -617,10 +629,10 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.value(), a._default(), a._enum(), a.items()) - && empty(a.type(), a.format(), a.collectionFormat(), a.pattern(), a.$ref(), a.maximum(), a.minimum(), a.multipleOf()) - && empty(a.exclusiveMaximum(), a.exclusiveMinimum(), a.uniqueItems()) - && empty(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()); + allEmpty(a.value(), a._default(), a._enum(), a.items()) + && allEmpty(a.type(), a.format(), a.collectionFormat(), a.pattern(), a.$ref(), a.maximum(), a.minimum(), a.multipleOf()) + && allFalse(a.exclusiveMaximum(), a.exclusiveMinimum(), a.uniqueItems()) + && allMinusOne(a.maxLength(), a.minLength(), a.maxItems(), a.minItems()); } /** @@ -633,56 +645,92 @@ public class AnnotationUtils { if (a == null) return true; return - empty(a.description(), a._enum(), a.example(), a.api()) - && empty(a.name(), a.value(), a.type(), a.format(), a.pattern(), a.maximum(), a.minimum(), a.multipleOf()) - && empty(a.exclusiveMaximum(), a.exclusiveMinimum()) - && empty(a.maxLength(), a.minLength()) + allEmpty(a.description(), a._enum(), a.example(), a.api()) + && allEmpty(a.name(), a.value(), a.type(), a.format(), a.pattern(), a.maximum(), a.minimum(), a.multipleOf()) + && allFalse(a.exclusiveMaximum(), a.exclusiveMinimum()) + && allMinusOne(a.maxLength(), a.minLength()) && empty(a.items()); } /** - * Returns true if the specified annotation contains all default values. + * Returns true if all the specified strings are empty or null. * - * @param a The annotation to check. - * @return true if the specified annotation contains all default values. + * @param strings The strings to test. + * @return true if all the specified strings are empty or null. */ - public static boolean empty(ResourceSwagger a) { - if (a == null) - return true; - return - empty(a.version()) - && empty(a.title(), a.description(), a.value()) - && empty(a.contact()) - && empty(a.license()) - && empty(a.externalDocs()) - && a.tags().length == 0; - } - - private static boolean empty(String...strings) { + protected static boolean allEmpty(String...strings) { for (String s : strings) - if (! s.isEmpty()) + if (s != null && ! s.isEmpty()) return false; return true; } - private static boolean empty(String[]...strings) { + /** + * Returns true if all the specified strings are empty or null. + * + * @param strings The strings to test. + * @return true if all the specified strings are empty or null. + */ + protected static boolean allEmpty(String[]...strings) { for (String[] s : strings) - if (s.length != 0) + if (s.length != 0 || ! allEmpty(s)) return false; return true; } - private static boolean empty(boolean...booleans) { + /** + * Returns true if all the specified booleans are false. + * + * @param booleans The booleans to test. + * @return true if all the specified booleans are false. + */ + protected static boolean allFalse(boolean...booleans) { for (boolean b : booleans) if (b) return false; return true; } - private static boolean empty(long...longs) { + /** + * Returns true if all the specified longs are -1. + * + * @param longs The booleans to test. + * @return true if all the specified longs are -1. + */ + protected static boolean allMinusOne(long...longs) { for (long i : longs) if (i != -1) return false; return true; } + + private static Set toSet(String[] s) { + return toSet(joinnl(s)); + } + + private static Set toSet(String s) { + if (isEmpty(s)) + return null; + Set set = new ASet<>(); + try { + for (Object o : StringUtils.parseListOrCdl(s)) + set.add(o.toString()); + } catch (ParseException e) { + throw new RuntimeException(e); + } + return set; + } + + final static ObjectMap toObjectMap(String[] ss) { + String s = joinnl(ss); + if (s.isEmpty()) + return null; + if (! isObjectMap(s, true)) + s = "{" + s + "}"; + try { + return new ObjectMap(s); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } } diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Body.java similarity index 84% rename from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java rename to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Body.java index 2321d3a..d3d37e7 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Body.java @@ -10,7 +10,7 @@ // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * // * specific language governing permissions and limitations under the License. * // *************************************************************************************************************************** -package org.apache.juneau.rest.annotation; +package org.apache.juneau.http.annotation; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; @@ -21,9 +21,12 @@ import java.nio.charset.*; import java.util.logging.*; import org.apache.juneau.*; +import org.apache.juneau.httppart.*; +import org.apache.juneau.httppart.oapi.*; import org.apache.juneau.json.*; import org.apache.juneau.jsonschema.*; -import org.apache.juneau.rest.exception.*; +import org.apache.juneau.remoteable.*; +import org.apache.juneau.serializer.*; /** * REST request body annotation. @@ -31,6 +34,18 @@ import org.apache.juneau.rest.exception.*; *

* Identifies a POJO to be used as the body of an HTTP request. * + *

+ * Can be used in the following locations: + *

    + *
  • Java method arguments of client-side REST interface proxies. + *
  • Java method arguments of server-side REST Java methods and/or their class types. + *
+ * + *
Server-side REST
+ * + *

+ * On server-side REST, this annotation can be applied to method parameters or parameter classes to identify them as the body of an HTTP request. + * *

Examples:
*

* // Used on parameter @@ -88,9 +103,9 @@ import org.apache.juneau.rest.exception.*; * This annotation can be applied to the following: *

    *
  • - * Parameters on a {@link RestMethod @RestMethod}-annotated method. + * Parameters on a @RestMethod-annotated method. *
  • - * POJO classes used as parameters on a {@link RestMethod @RestMethod}-annotated method. + * POJO classes used as parameters on a @RestMethod-annotated method. *
* *

@@ -162,13 +177,66 @@ import org.apache.juneau.rest.exception.*; *