From fa55d3d1ea3acb80c291f9e4c8b3a1cee668929a Mon Sep 17 00:00:00 2001 From: Thierry Boileau Date: Sat, 4 Jul 2026 19:27:21 +0200 Subject: [PATCH 1/2] Issue #1516: Increase test coverage to meet raised jacoco minimum Adds unit tests across org.restlet core and the velocity, jackson, spring, thymeleaf, crypto, and xml extensions to bring each module above the jacoco minimum coverage raised from 0.50 to 0.70. Also fixes a real bug found along the way: WrapperRequest.setAccessControlRequestHeaders/setAccessControlRequestMethod called super.set...() instead of delegating to the wrapped request, which threw a NullPointerException on any real usage since the corresponding getters were already overridden to delegate. Co-Authored-By: Claude Sonnet 5 --- .../ext/crypto/AwsAuthenticatorTestCase.java | 80 +++++++ .../ext/crypto/DigestUtilsTestCase.java | 113 ++++++++++ .../internal/AwsUtilsQueryTestCase.java | 72 ++++++ .../internal/HttpAwsQueryHelperTestCase.java | 64 ++++++ .../HttpAzureSharedKeyHelperTestCase.java | 89 ++++++++ .../HttpAzureSharedKeyLiteHelperTestCase.java | 76 +++++++ .../ext/jackson/JacksonConverterTestCase.java | 192 ++++++++++++++++ .../ext/spring/SpringContextTestCase.java | 85 +++++++ .../ext/spring/SpringResourceTestCase.java | 105 +++++++++ .../spring/SpringContextTestCase.properties | 1 + .../ext/spring/SpringContextTestCase.xml | 7 + .../ext/thymeleaf/TemplateFilterTestCase.java | 152 +++++++++++++ .../velocity/VelocityConverterTestCase.java | 147 ++++++++++++ .../ext/xml/SaxRepresentationTestCase.java | 57 +++++ .../restlet/ext/xml/TransformerTestCase.java | 117 ++++++++++ .../internal/AbstractXmlReaderTestCase.java | 93 ++++++++ .../xml/internal/ContextResolverTestCase.java | 62 ++++++ .../java/org/restlet/util/WrapperRequest.java | 4 +- .../org/restlet/data/ExpectationTestCase.java | 73 ++++++ .../org/restlet/data/WarningTestCase.java | 46 ++++ .../engine/adapter/JettyHandlerTestCase.java | 40 ++++ .../DecodeRepresentationTestCase.java | 97 ++++++++ .../EncodeRepresentationTestCase.java | 210 ++++++++++++++++++ .../engine/application/EncoderTestCase.java | 122 ++++++++++ .../header/ExpectationWriterTestCase.java | 52 +++++ .../engine/header/MethodReaderTestCase.java | 37 +++ .../engine/header/RangeWriterTestCase.java | 113 ++++++++++ .../engine/header/StringReaderTestCase.java | 36 +++ .../engine/header/WarningReaderTestCase.java | 65 ++++++ .../log/AccessLogFileHandlerTestCase.java | 70 ++++++ .../DefaultAccessLogFormatterTestCase.java | 28 +++ .../engine/log/IdentClientTestCase.java | 38 ++++ .../log/LoggingThreadFactoryTestCase.java | 70 ++++++ .../engine/log/SimplerFormatterTestCase.java | 44 ++++ ...WrapperSslServerSocketFactoryTestCase.java | 97 ++++++++ .../engine/util/BeanInfoUtilsTestCase.java | 62 ++++++ .../util/DefaultSaxHandlerTestCase.java | 75 +++++++ .../engine/util/ListUtilsTestCase.java | 44 ++++ .../engine/util/MapResolverTestCase.java | 31 +++ .../org/restlet/engine/util/PoolTestCase.java | 73 ++++++ .../BufferingRepresentationTestCase.java | 72 ++++++ .../ByteArrayRepresentationTestCase.java | 62 ++++++ .../ReaderRepresentationTestCase.java | 67 ++++++ .../WriterRepresentationTestCase.java | 58 +++++ .../restlet/routing/ExtractorTestCase.java | 157 +++++++++++++ .../CertificateAuthenticatorTestCase.java | 140 ++++++++++++ .../ConfidentialAuthorizerTestCase.java | 41 ++++ .../security/MethodAuthorizerTestCase.java | 109 +++++++++ .../restlet/service/CorsServiceTestCase.java | 82 +++++++ .../org/restlet/util/WrapperMapTestCase.java | 56 +++++ .../restlet/util/WrapperRequestTestCase.java | 143 ++++++++++++ .../restlet/util/WrapperResponseTestCase.java | 153 +++++++++++++ .../restlet/util/WrapperRestletTestCase.java | 64 ++++++ pom.xml | 4 +- 54 files changed, 4243 insertions(+), 4 deletions(-) create mode 100644 org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/AwsAuthenticatorTestCase.java create mode 100644 org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/DigestUtilsTestCase.java create mode 100644 org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/AwsUtilsQueryTestCase.java create mode 100644 org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/HttpAwsQueryHelperTestCase.java create mode 100644 org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/HttpAzureSharedKeyHelperTestCase.java create mode 100644 org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/HttpAzureSharedKeyLiteHelperTestCase.java create mode 100644 org.restlet.ext.jackson/src/test/java/org/restlet/ext/jackson/JacksonConverterTestCase.java create mode 100644 org.restlet.ext.spring/src/test/java/org/restlet/ext/spring/SpringContextTestCase.java create mode 100644 org.restlet.ext.spring/src/test/java/org/restlet/ext/spring/SpringResourceTestCase.java create mode 100644 org.restlet.ext.spring/src/test/resources/org/restlet/ext/spring/SpringContextTestCase.properties create mode 100644 org.restlet.ext.spring/src/test/resources/org/restlet/ext/spring/SpringContextTestCase.xml create mode 100644 org.restlet.ext.thymeleaf/src/test/java/org/restlet/ext/thymeleaf/TemplateFilterTestCase.java create mode 100644 org.restlet.ext.velocity/src/test/java/org/restlet/ext/velocity/VelocityConverterTestCase.java create mode 100644 org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/internal/AbstractXmlReaderTestCase.java create mode 100644 org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/internal/ContextResolverTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/data/ExpectationTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/data/WarningTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/adapter/JettyHandlerTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/application/DecodeRepresentationTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/application/EncodeRepresentationTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/application/EncoderTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/header/ExpectationWriterTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/header/MethodReaderTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/header/RangeWriterTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/header/StringReaderTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/header/WarningReaderTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/log/AccessLogFileHandlerTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/log/DefaultAccessLogFormatterTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/log/IdentClientTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/log/LoggingThreadFactoryTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/log/SimplerFormatterTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/ssl/WrapperSslServerSocketFactoryTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/util/BeanInfoUtilsTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/util/DefaultSaxHandlerTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/util/ListUtilsTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/util/MapResolverTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/engine/util/PoolTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/representation/BufferingRepresentationTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/representation/ByteArrayRepresentationTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/representation/ReaderRepresentationTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/representation/WriterRepresentationTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/routing/ExtractorTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/security/CertificateAuthenticatorTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/security/ConfidentialAuthorizerTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/security/MethodAuthorizerTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/service/CorsServiceTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/util/WrapperMapTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/util/WrapperRequestTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/util/WrapperResponseTestCase.java create mode 100644 org.restlet/src/test/java/org/restlet/util/WrapperRestletTestCase.java diff --git a/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/AwsAuthenticatorTestCase.java b/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/AwsAuthenticatorTestCase.java new file mode 100644 index 0000000000..f2075d09f2 --- /dev/null +++ b/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/AwsAuthenticatorTestCase.java @@ -0,0 +1,80 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.ext.crypto; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.restlet.Context; +import org.restlet.data.ChallengeScheme; +import org.restlet.ext.crypto.internal.AwsVerifier; +import org.restlet.security.MapVerifier; +import org.restlet.security.Verifier; + +/** Unit tests for {@link AwsAuthenticator}. */ +class AwsAuthenticatorTestCase { + + @Test + void constructor_withContextAndRealm_isNotOptional() { + AwsAuthenticator authenticator = new AwsAuthenticator(new Context(), "realm"); + assertFalse(authenticator.isOptional()); + assertEquals(ChallengeScheme.HTTP_AWS_S3, authenticator.getScheme()); + assertNotNull(authenticator.getVerifier()); + } + + @Test + void constructor_withOptionalFlag_setsOptional() { + AwsAuthenticator authenticator = new AwsAuthenticator(new Context(), true, "realm"); + assertTrue(authenticator.isOptional()); + } + + @Test + void constructor_withExplicitVerifier_usesIt() { + AwsVerifier verifier = new AwsVerifier(null); + AwsAuthenticator authenticator = + new AwsAuthenticator(new Context(), false, "realm", verifier); + assertSame(verifier, authenticator.getVerifier()); + } + + @Test + void maxRequestAge_getterAndSetter_delegateToVerifier() { + AwsAuthenticator authenticator = new AwsAuthenticator(new Context(), "realm"); + authenticator.setMaxRequestAge(1000L); + assertEquals(1000L, authenticator.getMaxRequestAge()); + } + + @Test + void wrappedVerifier_getterAndSetter_delegateToVerifier() { + AwsAuthenticator authenticator = new AwsAuthenticator(new Context(), "realm"); + MapVerifier wrapped = new MapVerifier(); + authenticator.setWrappedVerifier(wrapped); + assertSame(wrapped, authenticator.getWrappedVerifier()); + } + + @Test + void setVerifier_withNonAwsVerifier_throwsIllegalArgumentException() { + AwsAuthenticator authenticator = new AwsAuthenticator(new Context(), "realm"); + Verifier notAnAwsVerifier = new MapVerifier(); + assertThrows( + IllegalArgumentException.class, () -> authenticator.setVerifier(notAnAwsVerifier)); + } + + @Test + void setVerifier_withAwsVerifier_replacesIt() { + AwsAuthenticator authenticator = new AwsAuthenticator(new Context(), "realm"); + AwsVerifier newVerifier = new AwsVerifier(null); + authenticator.setVerifier(newVerifier); + assertSame(newVerifier, authenticator.getVerifier()); + } +} diff --git a/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/DigestUtilsTestCase.java b/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/DigestUtilsTestCase.java new file mode 100644 index 0000000000..05096e826b --- /dev/null +++ b/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/DigestUtilsTestCase.java @@ -0,0 +1,113 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.ext.crypto; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Base64; +import org.junit.jupiter.api.Test; +import org.restlet.data.Digest; + +/** Unit tests for {@link DigestUtils}. */ +class DigestUtilsTestCase { + + @Test + void toMd5_string_matchesKnownVector() { + assertEquals("68e109f0f40ca72a15e05cc22786f8e6", DigestUtils.toMd5("HelloWorld")); + } + + @Test + void toMd5_withCharset_matchesKnownVector() throws Exception { + assertEquals("68e109f0f40ca72a15e05cc22786f8e6", DigestUtils.toMd5("HelloWorld", "UTF-8")); + } + + @Test + void toSha1_string_isDeterministicBase64() { + String result = DigestUtils.toSha1("HelloWorld"); + assertEquals(result, DigestUtils.toSha1("HelloWorld")); + assertEquals(28, result.length()); + } + + @Test + void toSha1_withCharset_isDeterministic() throws Exception { + assertEquals( + DigestUtils.toSha1("HelloWorld", "UTF-8"), + DigestUtils.toSha1("HelloWorld", "UTF-8")); + } + + @Test + void digest_md5Algorithm_delegatesToToMd5() { + assertEquals( + DigestUtils.toMd5("HelloWorld"), + DigestUtils.digest("HelloWorld", Digest.ALGORITHM_MD5)); + } + + @Test + void digest_sha1Algorithm_delegatesToToSha1() { + assertEquals( + DigestUtils.toSha1("HelloWorld"), + DigestUtils.digest("HelloWorld", Digest.ALGORITHM_SHA_1)); + } + + @Test + void digest_unsupportedAlgorithm_throwsIllegalArgumentException() { + assertThrows( + IllegalArgumentException.class, + () -> DigestUtils.digest("HelloWorld", "unsupported")); + } + + @Test + void digest_charArrayOverload_matchesStringOverload() { + assertArrayEquals( + DigestUtils.digest("HelloWorld", Digest.ALGORITHM_MD5).toCharArray(), + DigestUtils.digest("HelloWorld".toCharArray(), Digest.ALGORITHM_MD5)); + } + + @Test + void toHMacSha256_bytesKey_matchesKnownVector() { + byte[] result = DigestUtils.toHMacSha256("hello", "secret-key".getBytes()); + assertEquals( + "mOf/uWS7Wj+QLbH8EBpbqpi28s1WhYIQydcPJqx2L8c=", + Base64.getEncoder().encodeToString(result)); + } + + @Test + void toHMacSha256_stringKey_matchesBytesKeyOverload() { + assertArrayEquals( + DigestUtils.toHMacSha256("hello", "secret-key".getBytes()), + DigestUtils.toHMacSha256("hello", "secret-key")); + } + + @Test + void toHMacSha1_bytesKey_matchesKnownVector() { + byte[] result = DigestUtils.toHMacSha1("hello", "secret-key".getBytes()); + assertEquals("J5rb+6R5G3Md2aC4ofFuty27aR0=", Base64.getEncoder().encodeToString(result)); + } + + @Test + void toHMacSha1_stringKey_matchesBytesKeyOverload() { + assertArrayEquals( + DigestUtils.toHMacSha1("hello", "secret-key".getBytes()), + DigestUtils.toHMacSha1("hello", "secret-key")); + } + + @Test + void toHttpDigest_withSecret_hashesIdentifierRealmAndSecret() { + String expected = DigestUtils.toMd5("user:realm:pass"); + assertEquals(expected, DigestUtils.toHttpDigest("user", "pass".toCharArray(), "realm")); + } + + @Test + void toHttpDigest_withNullSecret_returnsNull() { + assertNull(DigestUtils.toHttpDigest("user", null, "realm")); + } +} diff --git a/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/AwsUtilsQueryTestCase.java b/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/AwsUtilsQueryTestCase.java new file mode 100644 index 0000000000..d9ffbc73ec --- /dev/null +++ b/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/AwsUtilsQueryTestCase.java @@ -0,0 +1,72 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.ext.crypto.internal; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.restlet.data.Method; +import org.restlet.data.Parameter; +import org.restlet.data.Reference; + +/** Unit tests for the query-signature related methods of {@link AwsUtils}. */ +class AwsUtilsQueryTestCase { + + private List params() { + List params = new ArrayList<>(); + params.add(new Parameter("Version", "2009-04-15")); + params.add(new Parameter("Action", "ListDomains")); + return params; + } + + @Test + void getQueryStringToSign_sortsParametersAndConcatenatesFields() { + Reference resourceRef = new Reference("http://sdb.amazonaws.com/"); + + String result = AwsUtils.getQueryStringToSign(Method.GET, resourceRef, params()); + + assertEquals("GET\nsdb.amazonaws.com\n/\nAction=ListDomains&Version=2009-04-15", result); + } + + @Test + void getQueryStringToSign_nullMethod_omitsMethodName() { + Reference resourceRef = new Reference("http://sdb.amazonaws.com/"); + + String result = AwsUtils.getQueryStringToSign(null, resourceRef, new ArrayList<>()); + + assertEquals("\nsdb.amazonaws.com\n/\n", result); + } + + @Test + void getQuerySignature_matchesKnownVector() { + Reference resourceRef = new Reference("http://sdb.amazonaws.com/"); + + String signature = + AwsUtils.getQuerySignature( + Method.GET, resourceRef, params(), "mysecret".toCharArray()); + + assertEquals("DG2zC7EgmtLBDdwPHV71VBw4mPpvIl1zymtFXAl/trQ=", signature); + } + + @Test + void getHmacSha256Signature_isDeterministic() { + String signature1 = AwsUtils.getHmacSha256Signature("hello", "secret".toCharArray()); + String signature2 = AwsUtils.getHmacSha256Signature("hello", "secret".toCharArray()); + assertEquals(signature1, signature2); + } + + @Test + void getHmacSha1Signature_isDeterministic() { + String signature1 = AwsUtils.getHmacSha1Signature("hello", "secret".toCharArray()); + String signature2 = AwsUtils.getHmacSha1Signature("hello", "secret".toCharArray()); + assertEquals(signature1, signature2); + } +} diff --git a/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/HttpAwsQueryHelperTestCase.java b/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/HttpAwsQueryHelperTestCase.java new file mode 100644 index 0000000000..c2d9917474 --- /dev/null +++ b/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/HttpAwsQueryHelperTestCase.java @@ -0,0 +1,64 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.ext.crypto.internal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.restlet.Request; +import org.restlet.data.ChallengeResponse; +import org.restlet.data.ChallengeScheme; +import org.restlet.data.Method; +import org.restlet.data.Reference; + +/** Unit tests for {@link HttpAwsQueryHelper}. */ +class HttpAwsQueryHelperTestCase { + + @Test + void constructor_registersAwsQueryScheme() { + HttpAwsQueryHelper helper = new HttpAwsQueryHelper(); + assertEquals(ChallengeScheme.HTTP_AWS_QUERY, helper.getChallengeScheme()); + } + + @Test + void updateReference_withoutActionParameter_returnsSameReference() { + HttpAwsQueryHelper helper = new HttpAwsQueryHelper(); + Request request = new Request(Method.GET, "http://sdb.amazonaws.com/"); + Reference resourceRef = new Reference("http://sdb.amazonaws.com/"); + + Reference result = helper.updateReference(resourceRef, null, request); + + assertSame(resourceRef, result); + } + + @Test + void updateReference_withActionParameter_signsAndAppendsParameters() { + HttpAwsQueryHelper helper = new HttpAwsQueryHelper(); + ChallengeResponse challengeResponse = + new ChallengeResponse( + ChallengeScheme.HTTP_AWS_QUERY, "myaccesskey", "mysecret".toCharArray()); + Request request = new Request(Method.GET, "http://sdb.amazonaws.com/?Action=ListDomains"); + request.setChallengeResponse(challengeResponse); + Reference resourceRef = new Reference("http://sdb.amazonaws.com/?Action=ListDomains"); + + Reference result = helper.updateReference(resourceRef, challengeResponse, request); + + assertNotSame(resourceRef, result); + String query = result.getQuery(); + assertTrue(query.contains("AWSAccessKeyId=myaccesskey")); + assertTrue(query.contains("SignatureMethod=HmacSHA256")); + assertTrue(query.contains("SignatureVersion=2")); + assertTrue(query.contains("Version=2009-04-15")); + assertTrue(query.contains("Timestamp=")); + assertTrue(query.contains("Signature=")); + } +} diff --git a/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/HttpAzureSharedKeyHelperTestCase.java b/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/HttpAzureSharedKeyHelperTestCase.java new file mode 100644 index 0000000000..c3b0ed3da4 --- /dev/null +++ b/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/HttpAzureSharedKeyHelperTestCase.java @@ -0,0 +1,89 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.ext.crypto.internal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.restlet.Request; +import org.restlet.data.ChallengeResponse; +import org.restlet.data.ChallengeScheme; +import org.restlet.data.Header; +import org.restlet.data.Method; +import org.restlet.engine.header.ChallengeWriter; +import org.restlet.engine.header.HeaderConstants; +import org.restlet.util.Series; + +/** Unit tests for {@link HttpAzureSharedKeyHelper}. */ +class HttpAzureSharedKeyHelperTestCase { + + @Test + void constructor_registersAzureSharedKeyScheme() { + HttpAzureSharedKeyHelper helper = new HttpAzureSharedKeyHelper(); + assertEquals(ChallengeScheme.HTTP_AZURE_SHAREDKEY, helper.getChallengeScheme()); + } + + @Test + void formatResponse_withoutOptionalHeaders_addsDateHeaderAndFormatsCredential() { + HttpAzureSharedKeyHelper helper = new HttpAzureSharedKeyHelper(); + Request request = + new Request(Method.GET, "http://myaccount.blob.core.windows.net/container"); + ChallengeResponse challenge = + new ChallengeResponse( + ChallengeScheme.HTTP_AZURE_SHAREDKEY, + "myaccount", + "c2VjcmV0".toCharArray()); + Series

httpHeaders = new Series<>(Header.class); + + ChallengeWriter cw = new ChallengeWriter(); + helper.formatResponse(cw, challenge, request, httpHeaders); + + String result = cw.toString(); + assertTrue(result.startsWith("myaccount:")); + assertNotNull(httpHeaders.getFirstValue(HeaderConstants.HEADER_DATE, true)); + } + + @Test + void formatResponse_withHeadersAndCompQuery_isDeterministic() { + HttpAzureSharedKeyHelper helper = new HttpAzureSharedKeyHelper(); + Request request = + new Request( + Method.PUT, + "http://myaccount.blob.core.windows.net/container/blob?comp=metadata"); + ChallengeResponse challenge = + new ChallengeResponse( + ChallengeScheme.HTTP_AZURE_SHAREDKEY, + "myaccount", + "c2VjcmV0".toCharArray()); + + Series
httpHeaders1 = new Series<>(Header.class); + httpHeaders1.add(HeaderConstants.HEADER_CONTENT_TYPE, "application/octet-stream"); + httpHeaders1.add(HeaderConstants.HEADER_CONTENT_MD5, "abc123"); + httpHeaders1.add(HeaderConstants.HEADER_DATE, "Wed, 21 Oct 2015 07:28:00 GMT"); + httpHeaders1.add("x-ms-version", "2020-02-10"); + httpHeaders1.add("x-ms-blob-type", "BlockBlob"); + + Series
httpHeaders2 = new Series<>(Header.class); + httpHeaders2.add(HeaderConstants.HEADER_CONTENT_TYPE, "application/octet-stream"); + httpHeaders2.add(HeaderConstants.HEADER_CONTENT_MD5, "abc123"); + httpHeaders2.add(HeaderConstants.HEADER_DATE, "Wed, 21 Oct 2015 07:28:00 GMT"); + httpHeaders2.add("x-ms-version", "2020-02-10"); + httpHeaders2.add("x-ms-blob-type", "BlockBlob"); + + ChallengeWriter cw1 = new ChallengeWriter(); + helper.formatResponse(cw1, challenge, request, httpHeaders1); + + ChallengeWriter cw2 = new ChallengeWriter(); + helper.formatResponse(cw2, challenge, request, httpHeaders2); + + assertEquals(cw1.toString(), cw2.toString()); + } +} diff --git a/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/HttpAzureSharedKeyLiteHelperTestCase.java b/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/HttpAzureSharedKeyLiteHelperTestCase.java new file mode 100644 index 0000000000..72272f1b61 --- /dev/null +++ b/org.restlet.ext.crypto/src/test/java/org/restlet/ext/crypto/internal/HttpAzureSharedKeyLiteHelperTestCase.java @@ -0,0 +1,76 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.ext.crypto.internal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.restlet.Request; +import org.restlet.data.ChallengeResponse; +import org.restlet.data.ChallengeScheme; +import org.restlet.data.Header; +import org.restlet.data.Method; +import org.restlet.engine.header.ChallengeWriter; +import org.restlet.engine.header.HeaderConstants; +import org.restlet.util.Series; + +/** Unit tests for {@link HttpAzureSharedKeyLiteHelper}. */ +class HttpAzureSharedKeyLiteHelperTestCase { + + @Test + void constructor_registersAzureSharedKeyLiteScheme() { + HttpAzureSharedKeyLiteHelper helper = new HttpAzureSharedKeyLiteHelper(); + assertEquals(ChallengeScheme.HTTP_AZURE_SHAREDKEY_LITE, helper.getChallengeScheme()); + } + + @Test + void formatResponse_withoutDateHeader_addsFreshDateHeader() { + HttpAzureSharedKeyLiteHelper helper = new HttpAzureSharedKeyLiteHelper(); + Request request = + new Request(Method.GET, "http://myaccount.table.core.windows.net/mytable"); + ChallengeResponse challenge = + new ChallengeResponse( + ChallengeScheme.HTTP_AZURE_SHAREDKEY_LITE, + "myaccount", + "c2VjcmV0".toCharArray()); + Series

httpHeaders = new Series<>(Header.class); + + ChallengeWriter cw = new ChallengeWriter(); + helper.formatResponse(cw, challenge, request, httpHeaders); + + assertTrue(cw.toString().startsWith("myaccount:")); + assertNotNull(httpHeaders.getFirstValue(HeaderConstants.HEADER_DATE, true)); + } + + @Test + void formatResponse_withXmsDateHeader_usesItInsteadOfDateHeader() { + HttpAzureSharedKeyLiteHelper helper = new HttpAzureSharedKeyLiteHelper(); + Request request = + new Request( + Method.GET, + "http://myaccount.table.core.windows.net/mytable?comp=metadata"); + ChallengeResponse challenge = + new ChallengeResponse( + ChallengeScheme.HTTP_AZURE_SHAREDKEY_LITE, + "myaccount", + "c2VjcmV0".toCharArray()); + Series
httpHeaders = new Series<>(Header.class); + httpHeaders.add("x-ms-date", "Wed, 21 Oct 2015 07:28:00 GMT"); + httpHeaders.add(HeaderConstants.HEADER_DATE, "should-be-ignored"); + + ChallengeWriter cw = new ChallengeWriter(); + helper.formatResponse(cw, challenge, request, httpHeaders); + + assertTrue(cw.toString().startsWith("myaccount:")); + assertEquals( + "should-be-ignored", httpHeaders.getFirstValue(HeaderConstants.HEADER_DATE, true)); + } +} diff --git a/org.restlet.ext.jackson/src/test/java/org/restlet/ext/jackson/JacksonConverterTestCase.java b/org.restlet.ext.jackson/src/test/java/org/restlet/ext/jackson/JacksonConverterTestCase.java new file mode 100644 index 0000000000..6096f2b1a9 --- /dev/null +++ b/org.restlet.ext.jackson/src/test/java/org/restlet/ext/jackson/JacksonConverterTestCase.java @@ -0,0 +1,192 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.ext.jackson; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.restlet.data.MediaType; +import org.restlet.data.Preference; +import org.restlet.representation.Representation; +import org.restlet.representation.StringRepresentation; +import org.restlet.representation.Variant; + +/** Unit tests for {@link JacksonConverter}. */ +class JacksonConverterTestCase { + + private final JacksonConverter converter = new JacksonConverter(); + + @Test + void isCompatible_forSupportedMediaTypes_returnsTrue() { + assertTrue(converter.isCompatible(new Variant(MediaType.APPLICATION_JSON))); + assertTrue(converter.isCompatible(new Variant(MediaType.APPLICATION_JSON_SMILE))); + assertTrue(converter.isCompatible(new Variant(MediaType.APPLICATION_XML))); + assertTrue(converter.isCompatible(new Variant(MediaType.TEXT_XML))); + assertTrue(converter.isCompatible(new Variant(MediaType.APPLICATION_YAML))); + assertTrue(converter.isCompatible(new Variant(MediaType.TEXT_YAML))); + assertTrue(converter.isCompatible(new Variant(MediaType.TEXT_CSV))); + } + + @Test + void isCompatible_forUnsupportedMediaType_returnsFalse() { + assertFalse(converter.isCompatible(new Variant(MediaType.IMAGE_PNG))); + } + + @Test + void isCompatible_forNullVariant_returnsFalse() { + assertFalse(converter.isCompatible(null)); + } + + @Test + void getObjectClasses_forCompatibleVariant_returnsObjectAndJacksonRepresentation() { + List> result = converter.getObjectClasses(new Variant(MediaType.APPLICATION_JSON)); + assertEquals(List.of(Object.class, JacksonRepresentation.class), result); + } + + @Test + void getObjectClasses_forIncompatibleVariant_returnsNull() { + assertNull(converter.getObjectClasses(new Variant(MediaType.IMAGE_PNG))); + } + + @Test + void getVariants_forNonNullClass_returnsAllSupportedVariants() { + List variants = converter.getVariants(String.class); + assertEquals(7, variants.size()); + } + + @Test + void getVariants_forNullClass_returnsEmptyList() { + assertTrue(converter.getVariants(null).isEmpty()); + } + + @Test + void score_jacksonRepresentation_returnsOne() { + JacksonRepresentation source = + new JacksonRepresentation<>(MediaType.APPLICATION_JSON, "text"); + assertEquals(1.0f, converter.score(source, new Variant(MediaType.APPLICATION_JSON), null)); + } + + @Test + void score_nullTarget_returnsHalf() { + assertEquals(0.5f, converter.score("text", null, null)); + } + + @Test + void score_compatibleTarget_returnsPointEight() { + assertEquals(0.8f, converter.score("text", new Variant(MediaType.APPLICATION_JSON), null)); + } + + @Test + void score_incompatibleTarget_returnsHalf() { + assertEquals(0.5f, converter.score("text", new Variant(MediaType.IMAGE_PNG), null)); + } + + @Test + void scoreRepresentation_jacksonRepresentation_returnsOne() { + JacksonRepresentation source = + new JacksonRepresentation<>(MediaType.APPLICATION_JSON, "text"); + assertEquals(1.0f, converter.score(source, String.class, null)); + } + + @Test + void scoreRepresentation_forJacksonRepresentationTarget_returnsOne() { + assertEquals( + 1.0f, + converter.score( + new StringRepresentation("text", MediaType.TEXT_PLAIN), + JacksonRepresentation.class, + null)); + } + + @Test + void scoreRepresentation_forCompatibleSource_returnsPointEight() { + assertEquals( + 0.8f, + converter.score( + new StringRepresentation("text", MediaType.APPLICATION_JSON), + String.class, + null)); + } + + @Test + void scoreRepresentation_forIncompatibleSource_returnsMinusOne() { + assertEquals( + -1.0f, + converter.score( + new StringRepresentation("text", MediaType.IMAGE_PNG), String.class, null)); + } + + @Test + void toObject_fromJacksonRepresentation_returnsUnderlyingObject() throws Exception { + JacksonRepresentation source = + new JacksonRepresentation<>(MediaType.APPLICATION_JSON, "text"); + assertEquals("text", converter.toObject(source, String.class, null)); + } + + @Test + void toObject_fromJacksonRepresentation_forJacksonRepresentationTarget_returnsRepresentation() + throws Exception { + JacksonRepresentation source = + new JacksonRepresentation<>(MediaType.APPLICATION_JSON, "text"); + Object result = converter.toObject(source, JacksonRepresentation.class, null); + assertTrue(result instanceof JacksonRepresentation); + } + + @Test + void toObject_fromCompatibleRepresentation_returnsParsedObject() throws Exception { + StringRepresentation source = + new StringRepresentation("\"text\"", MediaType.APPLICATION_JSON); + assertEquals("text", converter.toObject(source, String.class, null)); + } + + @Test + void toObject_fromIncompatibleRepresentation_returnsNull() throws Exception { + StringRepresentation source = new StringRepresentation("text", MediaType.IMAGE_PNG); + assertNull(converter.toObject(source, String.class, null)); + } + + @Test + void toRepresentation_fromJacksonRepresentation_returnsSameInstance() { + JacksonRepresentation source = + new JacksonRepresentation<>(MediaType.APPLICATION_JSON, "text"); + Representation result = + converter.toRepresentation(source, new Variant(MediaType.APPLICATION_JSON), null); + assertEquals(source, result); + } + + @Test + void toRepresentation_withoutMediaType_defaultsToJson() { + Variant target = new Variant(); + Representation result = converter.toRepresentation("text", target, null); + assertEquals(MediaType.APPLICATION_JSON, target.getMediaType()); + assertTrue(result instanceof JacksonRepresentation); + } + + @Test + void toRepresentation_forIncompatibleTarget_returnsNull() { + Representation result = + converter.toRepresentation("text", new Variant(MediaType.IMAGE_PNG), null); + assertNull(result); + } + + @Test + void updatePreferences_addsAllSupportedMediaTypesWithFullPriority() { + List> preferences = new ArrayList<>(); + converter.updatePreferences(preferences, String.class); + assertEquals(7, preferences.size()); + for (Preference preference : preferences) { + assertEquals(1.0f, preference.getQuality()); + } + } +} diff --git a/org.restlet.ext.spring/src/test/java/org/restlet/ext/spring/SpringContextTestCase.java b/org.restlet.ext.spring/src/test/java/org/restlet/ext/spring/SpringContextTestCase.java new file mode 100644 index 0000000000..23f0e90960 --- /dev/null +++ b/org.restlet.ext.spring/src/test/java/org/restlet/ext/spring/SpringContextTestCase.java @@ -0,0 +1,85 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.ext.spring; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.restlet.Client; +import org.restlet.Context; +import org.restlet.data.Protocol; + +/** Unit tests for {@link SpringContext}. */ +class SpringContextTestCase { + + private Context restletContextWithClapDispatcher() { + Context context = new Context(); + context.setClientDispatcher(new Client(Protocol.CLAP)); + return context; + } + + @Test + void getRestletContext_returnsConstructorArgument() { + Context restletContext = new Context(); + SpringContext springContext = new SpringContext(restletContext); + assertSame(restletContext, springContext.getRestletContext()); + } + + @Test + void getPropertyConfigRefs_lazyInitializesToEmptyModifiableList() { + SpringContext springContext = new SpringContext(new Context()); + assertNotNull(springContext.getPropertyConfigRefs()); + assertTrue(springContext.getPropertyConfigRefs().isEmpty()); + springContext.getPropertyConfigRefs().add("some-ref"); + assertEquals(1, springContext.getPropertyConfigRefs().size()); + } + + @Test + void getXmlConfigRefs_lazyInitializesToEmptyModifiableList() { + SpringContext springContext = new SpringContext(new Context()); + assertNotNull(springContext.getXmlConfigRefs()); + assertTrue(springContext.getXmlConfigRefs().isEmpty()); + springContext.getXmlConfigRefs().add("some-ref"); + assertEquals(1, springContext.getXmlConfigRefs().size()); + } + + @Test + void refresh_withoutConfigRefs_refreshesEmptyContext() { + SpringContext springContext = new SpringContext(new Context()); + springContext.refresh(); + assertTrue(springContext.isActive()); + } + + @Test + void refresh_withPropertyConfigRef_loadsBeanDefinitionsFromProperties() { + SpringContext springContext = new SpringContext(restletContextWithClapDispatcher()); + springContext + .getPropertyConfigRefs() + .add("clap://class/org/restlet/ext/spring/SpringContextTestCase.properties"); + + springContext.refresh(); + + assertNotNull(springContext.getBean("myPropertyBean")); + } + + @Test + void refresh_withXmlConfigRef_loadsBeanDefinitionsFromXml() { + SpringContext springContext = new SpringContext(restletContextWithClapDispatcher()); + springContext + .getXmlConfigRefs() + .add("clap://class/org/restlet/ext/spring/SpringContextTestCase.xml"); + + springContext.refresh(); + + assertNotNull(springContext.getBean("myXmlBean")); + } +} diff --git a/org.restlet.ext.spring/src/test/java/org/restlet/ext/spring/SpringResourceTestCase.java b/org.restlet.ext.spring/src/test/java/org/restlet/ext/spring/SpringResourceTestCase.java new file mode 100644 index 0000000000..e219334b7c --- /dev/null +++ b/org.restlet.ext.spring/src/test/java/org/restlet/ext/spring/SpringResourceTestCase.java @@ -0,0 +1,105 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.ext.spring; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.io.InputStream; +import org.junit.jupiter.api.Test; +import org.restlet.engine.io.IoUtils; +import org.restlet.representation.Representation; +import org.restlet.representation.StringRepresentation; + +/** Unit tests for {@link SpringResource}. */ +class SpringResourceTestCase { + + @Test + void constructor_withNullRepresentation_throwsIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> new SpringResource(null)); + } + + @Test + void constructor_withoutDescription_usesDefaultDescription() { + SpringResource resource = new SpringResource(new StringRepresentation("text")); + assertEquals("Restlet Representation", resource.getDescription()); + } + + @Test + void constructor_withNullDescription_usesEmptyDescription() { + SpringResource resource = new SpringResource(new StringRepresentation("text"), null); + assertEquals("", resource.getDescription()); + } + + @Test + void constructor_withCustomDescription_usesIt() { + SpringResource resource = + new SpringResource(new StringRepresentation("text"), "my description"); + assertEquals("my description", resource.getDescription()); + } + + @Test + void existsAndIsOpen_alwaysReturnTrue() { + SpringResource resource = new SpringResource(new StringRepresentation("text")); + assertTrue(resource.exists()); + assertTrue(resource.isOpen()); + } + + @Test + void getInputStream_returnsUnderlyingStream() throws Exception { + SpringResource resource = new SpringResource(new StringRepresentation("hello")); + assertEquals("hello", IoUtils.toString(resource.getInputStream())); + } + + @Test + void getInputStream_readTwiceOnTransientRepresentation_throwsIllegalStateException() + throws Exception { + StringRepresentation transientRepresentation = new StringRepresentation("hello"); + transientRepresentation.setTransient(true); + SpringResource resource = new SpringResource(transientRepresentation); + + resource.getInputStream(); + + assertThrows(IllegalStateException.class, resource::getInputStream); + } + + @Test + void getInputStream_whenStreamIsNull_throwsIllegalStateException() { + Representation nullStreamRepresentation = + new StringRepresentation("hello") { + @Override + public InputStream getStream() throws IOException { + return null; + } + }; + SpringResource resource = new SpringResource(nullStreamRepresentation); + + assertThrows(IllegalStateException.class, resource::getInputStream); + } + + @Test + void equalsAndHashCode_basedOnWrappedRepresentation() { + StringRepresentation representation = new StringRepresentation("hello"); + SpringResource resource1 = new SpringResource(representation); + SpringResource resource2 = new SpringResource(representation); + SpringResource resource3 = + new SpringResource( + new StringRepresentation("other", org.restlet.data.MediaType.TEXT_HTML)); + + assertEquals(resource1, resource1); + assertEquals(resource1, resource2); + assertEquals(resource1.hashCode(), resource2.hashCode()); + assertNotEquals(resource1, resource3); + assertFalse(resource1.equals("not a resource")); + } +} diff --git a/org.restlet.ext.spring/src/test/resources/org/restlet/ext/spring/SpringContextTestCase.properties b/org.restlet.ext.spring/src/test/resources/org/restlet/ext/spring/SpringContextTestCase.properties new file mode 100644 index 0000000000..c0e7a28871 --- /dev/null +++ b/org.restlet.ext.spring/src/test/resources/org/restlet/ext/spring/SpringContextTestCase.properties @@ -0,0 +1 @@ +myPropertyBean.(class)=java.lang.Object diff --git a/org.restlet.ext.spring/src/test/resources/org/restlet/ext/spring/SpringContextTestCase.xml b/org.restlet.ext.spring/src/test/resources/org/restlet/ext/spring/SpringContextTestCase.xml new file mode 100644 index 0000000000..e152d6814c --- /dev/null +++ b/org.restlet.ext.spring/src/test/resources/org/restlet/ext/spring/SpringContextTestCase.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/org.restlet.ext.thymeleaf/src/test/java/org/restlet/ext/thymeleaf/TemplateFilterTestCase.java b/org.restlet.ext.thymeleaf/src/test/java/org/restlet/ext/thymeleaf/TemplateFilterTestCase.java new file mode 100644 index 0000000000..b7856931d9 --- /dev/null +++ b/org.restlet.ext.thymeleaf/src/test/java/org/restlet/ext/thymeleaf/TemplateFilterTestCase.java @@ -0,0 +1,152 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.ext.thymeleaf; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.junit.jupiter.api.Test; +import org.restlet.Context; +import org.restlet.Request; +import org.restlet.Response; +import org.restlet.data.Encoding; +import org.restlet.data.MediaType; +import org.restlet.data.Method; +import org.restlet.representation.Representation; +import org.restlet.representation.StringRepresentation; +import org.restlet.util.Resolver; + +/** Unit tests for {@link TemplateFilter}. */ +class TemplateFilterTestCase { + + private static final Encoding THYMELEAF = new Encoding("thymeleaf", "Thymeleaf"); + + private static class TestTemplateFilter extends TemplateFilter { + TestTemplateFilter() { + super(); + } + + TestTemplateFilter(org.restlet.Context context) { + super(context); + } + + TestTemplateFilter(org.restlet.Context context, org.restlet.Restlet next) { + super(context, next); + } + + TestTemplateFilter( + org.restlet.Context context, org.restlet.Restlet next, Map model) { + super(context, next, model); + } + + TestTemplateFilter( + org.restlet.Context context, org.restlet.Restlet next, Resolver resolver) { + super(context, next, resolver); + } + } + + private Request newRequest() { + Request request = new Request(Method.GET, "/"); + request.setEntity(new StringRepresentation("foo=bar", MediaType.APPLICATION_WWW_FORM)); + return request; + } + + private TemplateRepresentation templateEntity() { + TemplateRepresentation representation = + new TemplateRepresentation("myTemplate", Locale.ENGLISH, MediaType.TEXT_HTML); + representation.getEncodings().add(THYMELEAF); + return representation; + } + + @Test + void getLocale_defaultsToJvmDefault() { + assertEquals(Locale.getDefault(), new TestTemplateFilter().getLocale()); + } + + @Test + void afterHandle_noEntity_doesNothing() { + TestTemplateFilter filter = new TestTemplateFilter(new Context()); + Request request = newRequest(); + Response response = new Response(request); + + filter.afterHandle(request, response); + + assertNull(response.getEntity()); + } + + @Test + void afterHandle_entityWithoutThymeleafEncoding_leavesEntityUnchanged() { + TestTemplateFilter filter = new TestTemplateFilter(new Context()); + Request request = newRequest(); + Response response = new Response(request); + Representation entity = new StringRepresentation("plain", MediaType.TEXT_PLAIN); + response.setEntity(entity); + + filter.afterHandle(request, response); + + assertSame(entity, response.getEntity()); + } + + @Test + void afterHandle_withoutDataModel_usesRequestResponseResolver() { + TestTemplateFilter filter = new TestTemplateFilter(new Context()); + Request request = newRequest(); + Response response = new Response(request); + response.setEntity(templateEntity()); + + filter.afterHandle(request, response); + + Representation result = response.getEntity(); + assertTrue(result instanceof TemplateRepresentation); + TemplateRepresentation tr = (TemplateRepresentation) result; + assertEquals("myTemplate", tr.getTemplateName()); + assertEquals(MediaType.TEXT_HTML, tr.getMediaType()); + assertEquals("bar", tr.context.getVariable("foo")); + } + + @Test + void afterHandle_withMapDataModel_usesMap() { + Map model = new ConcurrentHashMap<>(); + model.put("key", "value"); + TestTemplateFilter filter = new TestTemplateFilter(new Context(), null, model); + Request request = newRequest(); + Response response = new Response(request); + response.setEntity(templateEntity()); + + filter.afterHandle(request, response); + + TemplateRepresentation tr = (TemplateRepresentation) response.getEntity(); + assertEquals("value", tr.context.getVariable("key")); + } + + @Test + void afterHandle_withResolverDataModel_usesResolver() { + Resolver resolver = + new Resolver<>() { + @Override + public Object resolve(String key) { + return "resolved-" + key; + } + }; + TestTemplateFilter filter = new TestTemplateFilter(new Context(), null, resolver); + Request request = newRequest(); + Response response = new Response(request); + response.setEntity(templateEntity()); + + filter.afterHandle(request, response); + + TemplateRepresentation tr = (TemplateRepresentation) response.getEntity(); + assertEquals("resolved-anyKey", tr.context.getVariable("anyKey")); + } +} diff --git a/org.restlet.ext.velocity/src/test/java/org/restlet/ext/velocity/VelocityConverterTestCase.java b/org.restlet.ext.velocity/src/test/java/org/restlet/ext/velocity/VelocityConverterTestCase.java new file mode 100644 index 0000000000..629db1249c --- /dev/null +++ b/org.restlet.ext.velocity/src/test/java/org/restlet/ext/velocity/VelocityConverterTestCase.java @@ -0,0 +1,147 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.ext.velocity; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.List; +import org.apache.velocity.Template; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.restlet.data.MediaType; +import org.restlet.data.Preference; +import org.restlet.engine.io.IoUtils; +import org.restlet.representation.StringRepresentation; +import org.restlet.representation.Variant; +import org.restlet.resource.ClientResource; + +/** Unit tests for {@link VelocityConverter}. */ +class VelocityConverterTestCase { + + private File testDir; + + private File testFile; + + private Template template; + + @BeforeEach + void setUp() throws Exception { + testDir = new File(System.getProperty("java.io.tmpdir"), "VelocityConverterTestCase"); + testDir.mkdir(); + testFile = File.createTempFile("test", ".vm", testDir); + + try (FileWriter fw = new FileWriter(testFile)) { + fw.write("Value=$value"); + } + + TemplateRepresentation tr = + new TemplateRepresentation(testFile.getName(), MediaType.TEXT_PLAIN); + tr.getEngine().setProperty("file.resource.loader.path", testDir.getAbsolutePath()); + template = tr.getTemplate(); + } + + @AfterEach + void tearDown() { + IoUtils.delete(testFile); + IoUtils.delete(testDir, true); + } + + @Test + void getObjectClasses_alwaysReturnsEmptyList() { + assertTrue( + new VelocityConverter() + .getObjectClasses(new Variant(MediaType.TEXT_PLAIN)) + .isEmpty()); + } + + @Test + void getVariants_forTemplate_returnsMediaTypeAll() { + List variants = new VelocityConverter().getVariants(Template.class); + assertEquals(1, variants.size()); + assertTrue(MediaType.ALL.isCompatible(((Variant) variants.getFirst()).getMediaType())); + } + + @Test + void getVariants_forOtherClass_returnsEmptyList() { + assertTrue(new VelocityConverter().getVariants(String.class).isEmpty()); + } + + @Test + void score_template_returnsOne() { + assertEquals( + 1.0f, + new VelocityConverter().score(template, new Variant(MediaType.TEXT_PLAIN), null)); + } + + @Test + void score_nonTemplate_returnsMinusOne() { + assertEquals( + -1.0f, + new VelocityConverter() + .score("not a template", new Variant(MediaType.TEXT_PLAIN), null)); + } + + @Test + void score_repr_alwaysReturnsMinusOne() { + assertEquals( + -1.0f, + new VelocityConverter() + .score(new StringRepresentation("text"), String.class, null)); + } + + @Test + void toObject_alwaysReturnsNull() { + assertNull( + new VelocityConverter() + .toObject(new StringRepresentation("text"), String.class, null)); + } + + @Test + void toRepresentation_nonTemplate_returnsNull() { + assertNull( + new VelocityConverter() + .toRepresentation("string", new Variant(MediaType.TEXT_PLAIN), null)); + } + + @Test + void toRepresentation_forTemplate_returnsTemplateRepresentationWithDataModel() + throws Exception { + ClientResource resource = new ClientResource("http://localhost/"); + + Object result = + new VelocityConverter() + .toRepresentation(template, new Variant(MediaType.TEXT_PLAIN), resource); + + assertTrue(result instanceof TemplateRepresentation); + TemplateRepresentation tr = (TemplateRepresentation) result; + assertEquals(MediaType.TEXT_PLAIN, tr.getMediaType()); + assertEquals("Value=$value", tr.getText()); + } + + @Test + void updatePreferences_forTemplate_addsMediaTypeAll() { + List> prefs = new ArrayList<>(); + new VelocityConverter().updatePreferences(prefs, Template.class); + assertEquals(1, prefs.size()); + assertEquals(MediaType.ALL, prefs.getFirst().getMetadata()); + } + + @Test + void updatePreferences_forOtherClass_doesNotModify() { + List> prefs = new ArrayList<>(); + new VelocityConverter().updatePreferences(prefs, String.class); + assertTrue(prefs.isEmpty()); + } +} diff --git a/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/SaxRepresentationTestCase.java b/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/SaxRepresentationTestCase.java index 9675246036..f3e0aa27fe 100644 --- a/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/SaxRepresentationTestCase.java +++ b/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/SaxRepresentationTestCase.java @@ -17,12 +17,15 @@ import java.io.IOException; import java.io.StringReader; +import java.io.StringWriter; import java.util.ArrayList; import java.util.List; +import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.sax.SAXSource; import org.junit.jupiter.api.Test; import org.restlet.data.MediaType; import org.restlet.representation.StringRepresentation; +import org.w3c.dom.Document; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.helpers.DefaultHandler; @@ -82,4 +85,58 @@ void release_clearsSource() throws Exception { sr.release(); assertNull(sr.getSaxSource()); } + + @Test + void defaultConstructor_usesTextXmlMediaType() { + SaxRepresentation sr = new SaxRepresentation(); + assertEquals(MediaType.TEXT_XML, sr.getMediaType()); + } + + @Test + void constructor_withInputSource_wrapsItInSaxSource() throws Exception { + InputSource inputSource = new InputSource(new StringReader(XML)); + SaxRepresentation sr = new SaxRepresentation(MediaType.TEXT_XML, inputSource); + assertNotNull(sr.getSaxSource()); + assertNotNull(sr.getInputSource()); + } + + @Test + void constructor_withDomDocument_wrapsItInSaxSource() throws Exception { + Document document = + DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(new org.xml.sax.InputSource(new StringReader(XML))); + SaxRepresentation sr = new SaxRepresentation(MediaType.TEXT_XML, document); + assertNotNull(sr.getSaxSource()); + } + + @Test + void constructor_withNullRepresentation_hasNullMediaType() { + SaxRepresentation sr = new SaxRepresentation((StringRepresentation) null); + assertNull(sr.getMediaType()); + } + + @Test + void getInputSource_withoutSaxSource_returnsNull() throws Exception { + SaxRepresentation sr = new SaxRepresentation(); + assertNull(sr.getInputSource()); + } + + @Test + void write_writer_serializesUsingXmlWriter() throws Exception { + SaxRepresentation sr = + new SaxRepresentation(new StringRepresentation(XML, MediaType.TEXT_XML)); + StringWriter writer = new StringWriter(); + sr.write(writer); + assertTrue(writer.toString().contains("")); + assertTrue(writer.toString().contains("text")); + } + + @Test + void setSaxSource_overridesSource() throws Exception { + SaxRepresentation sr = new SaxRepresentation(); + SAXSource source = new SAXSource(new InputSource(new StringReader(XML))); + sr.setSaxSource(source); + assertEquals(source, sr.getSaxSource()); + } } diff --git a/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/TransformerTestCase.java b/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/TransformerTestCase.java index c5d2c2371a..0e77c311a2 100644 --- a/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/TransformerTestCase.java +++ b/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/TransformerTestCase.java @@ -9,15 +9,25 @@ package org.restlet.ext.xml; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.List; import org.junit.jupiter.api.Test; import org.restlet.Component; +import org.restlet.Request; +import org.restlet.Response; +import org.restlet.data.CharacterSet; +import org.restlet.data.Encoding; +import org.restlet.data.Language; import org.restlet.data.MediaType; import org.restlet.representation.Representation; import org.restlet.representation.StringRepresentation; +import org.restlet.routing.Filter; /** * Test case for the Transformer class. @@ -108,4 +118,111 @@ void testTransform() throws Exception { assertEquals(this.output, result); } + + @Test + void constructor_setsDefaults() { + Transformer transformer = new Transformer(Transformer.MODE_REQUEST, this.xslt); + assertEquals(Transformer.MODE_REQUEST, transformer.getMode()); + assertSame(this.xslt, transformer.getTransformSheet()); + assertEquals(MediaType.APPLICATION_XML, transformer.getResultMediaType()); + assertNull(transformer.getResultCharacterSet()); + } + + @Test + void gettersAndSetters_roundTrip() { + Transformer transformer = new Transformer(Transformer.MODE_REQUEST, this.xslt); + + transformer.setMode(Transformer.MODE_RESPONSE); + assertEquals(Transformer.MODE_RESPONSE, transformer.getMode()); + + transformer.setResultCharacterSet(CharacterSet.UTF_8); + assertEquals(CharacterSet.UTF_8, transformer.getResultCharacterSet()); + + transformer.setResultMediaType(MediaType.TEXT_XML); + assertEquals(MediaType.TEXT_XML, transformer.getResultMediaType()); + + Representation otherSheet = new StringRepresentation("sheet"); + transformer.setTransformSheet(otherSheet); + assertSame(otherSheet, transformer.getTransformSheet()); + + assertTrue(transformer.getResultEncodings().isEmpty()); + transformer.setResultEncodings(List.of(Encoding.GZIP)); + assertEquals(List.of(Encoding.GZIP), transformer.getResultEncodings()); + + assertTrue(transformer.getResultLanguages().isEmpty()); + transformer.setResultLanguages(List.of(Language.ENGLISH)); + assertEquals(List.of(Language.ENGLISH), transformer.getResultLanguages()); + } + + @Test + void canTransform_alwaysReturnsTrue() { + Transformer transformer = new Transformer(Transformer.MODE_REQUEST, this.xslt); + assertTrue(transformer.canTransform(null)); + assertTrue(transformer.canTransform(this.source)); + } + + @Test + void beforeHandle_requestMode_transformsRequestEntity() { + Transformer transformer = new Transformer(Transformer.MODE_REQUEST, this.xslt); + Request request = new Request(); + request.setEntity(this.source); + Response response = new Response(request); + + int result = transformer.beforeHandle(request, response); + + assertEquals(Filter.CONTINUE, result); + assertTrue(request.getEntity() instanceof TransformRepresentation); + } + + @Test + void beforeHandle_responseMode_doesNotTransformRequestEntity() { + Transformer transformer = new Transformer(Transformer.MODE_RESPONSE, this.xslt); + Request request = new Request(); + request.setEntity(this.source); + Response response = new Response(request); + + transformer.beforeHandle(request, response); + + assertSame(this.source, request.getEntity()); + } + + @Test + void afterHandle_responseMode_transformsResponseEntity() { + Transformer transformer = new Transformer(Transformer.MODE_RESPONSE, this.xslt); + Request request = new Request(); + Response response = new Response(request); + response.setEntity(this.source); + + transformer.afterHandle(request, response); + + assertTrue(response.getEntity() instanceof TransformRepresentation); + } + + @Test + void afterHandle_requestMode_doesNotTransformResponseEntity() { + Transformer transformer = new Transformer(Transformer.MODE_REQUEST, this.xslt); + Request request = new Request(); + Response response = new Response(request); + response.setEntity(this.source); + + transformer.afterHandle(request, response); + + assertSame(this.source, response.getEntity()); + } + + @Test + void transform_withResultLanguagesAndEncodings_appliesThemToResult() { + Transformer transformer = new Transformer(Transformer.MODE_REQUEST, this.xslt); + transformer.setResultLanguages(List.of(Language.FRENCH)); + transformer.setResultEncodings(List.of(Encoding.GZIP)); + transformer.setResultCharacterSet(CharacterSet.UTF_8); + transformer.setResultMediaType(MediaType.TEXT_XML); + + Representation result = transformer.transform(this.source); + + assertTrue(result.getLanguages().contains(Language.FRENCH)); + assertTrue(result.getEncodings().contains(Encoding.GZIP)); + assertEquals(CharacterSet.UTF_8, result.getCharacterSet()); + assertEquals(MediaType.TEXT_XML, result.getMediaType()); + } } diff --git a/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/internal/AbstractXmlReaderTestCase.java b/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/internal/AbstractXmlReaderTestCase.java new file mode 100644 index 0000000000..49086790c4 --- /dev/null +++ b/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/internal/AbstractXmlReaderTestCase.java @@ -0,0 +1,93 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.ext.xml.internal; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.helpers.DefaultHandler; + +/** Unit tests for {@link AbstractXmlReader}. */ +class AbstractXmlReaderTestCase { + + private static class TestXmlReader extends AbstractXmlReader { + @Override + public void parse(InputSource input) {} + + @Override + public void parse(String systemId) {} + } + + @Test + void newInstance_hasNullHandlersAndFalseFeatures() { + TestXmlReader reader = new TestXmlReader(); + assertNull(reader.getContentHandler()); + assertNull(reader.getDTDHandler()); + assertNull(reader.getEntityResolver()); + assertNull(reader.getErrorHandler()); + assertFalse(reader.getFeature("any-feature")); + assertNull(reader.getProperty("any-property")); + } + + @Test + void contentHandler_setterAndGetter_roundTrip() { + TestXmlReader reader = new TestXmlReader(); + ContentHandler handler = new DefaultHandler(); + reader.setContentHandler(handler); + assertSame(handler, reader.getContentHandler()); + } + + @Test + void dtdHandler_setterAndGetter_roundTrip() { + TestXmlReader reader = new TestXmlReader(); + DTDHandler handler = new DefaultHandler(); + reader.setDTDHandler(handler); + assertSame(handler, reader.getDTDHandler()); + } + + @Test + void entityResolver_setterAndGetter_roundTrip() { + TestXmlReader reader = new TestXmlReader(); + EntityResolver resolver = new DefaultHandler(); + reader.setEntityResolver(resolver); + assertSame(resolver, reader.getEntityResolver()); + } + + @Test + void errorHandler_setterAndGetter_roundTrip() { + TestXmlReader reader = new TestXmlReader(); + ErrorHandler handler = new DefaultHandler(); + reader.setErrorHandler(handler); + assertSame(handler, reader.getErrorHandler()); + } + + @Test + void feature_setterAndGetter_roundTrip() { + TestXmlReader reader = new TestXmlReader(); + reader.setFeature("my-feature", true); + assertTrue(reader.getFeature("my-feature")); + assertFalse(reader.getFeature("other-feature")); + } + + @Test + void property_setterAndGetter_roundTrip() { + TestXmlReader reader = new TestXmlReader(); + Object value = new Object(); + reader.setProperty("my-property", value); + assertSame(value, reader.getProperty("my-property")); + } +} diff --git a/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/internal/ContextResolverTestCase.java b/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/internal/ContextResolverTestCase.java new file mode 100644 index 0000000000..6cd95bee3d --- /dev/null +++ b/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/internal/ContextResolverTestCase.java @@ -0,0 +1,62 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.ext.xml.internal; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import javax.xml.transform.Source; +import org.junit.jupiter.api.Test; +import org.restlet.Client; +import org.restlet.Context; +import org.restlet.data.Protocol; + +/** Unit tests for {@link ContextResolver}. */ +class ContextResolverTestCase { + + private Context clapContext() { + Context context = new Context(); + context.setClientDispatcher(new Client(Protocol.CLAP)); + return context; + } + + @Test + void resolve_withNullContext_returnsNull() { + ContextResolver resolver = new ContextResolver(null); + assertNull(resolver.resolve("clap://class/org/restlet/ext/xml/xslt/one/1st.xml", null)); + } + + @Test + void resolve_withAbsoluteHrefAndNoBase_returnsSource() { + ContextResolver resolver = new ContextResolver(clapContext()); + + Source result = resolver.resolve("clap://class/org/restlet/ext/xml/xslt/one/1st.xml", null); + + assertNotNull(result); + } + + @Test + void resolve_withRelativeHrefAndBase_returnsSource() { + ContextResolver resolver = new ContextResolver(clapContext()); + + Source result = + resolver.resolve("1st.xml", "clap://class/org/restlet/ext/xml/xslt/one/base.xsl"); + + assertNotNull(result); + } + + @Test + void resolve_withUnresolvableHref_returnsNull() { + ContextResolver resolver = new ContextResolver(clapContext()); + + Source result = resolver.resolve("clap://class/does/not/exist.xml", null); + + assertNull(result); + } +} diff --git a/org.restlet/src/main/java/org/restlet/util/WrapperRequest.java b/org.restlet/src/main/java/org/restlet/util/WrapperRequest.java index bef197704b..87d9f96aaf 100644 --- a/org.restlet/src/main/java/org/restlet/util/WrapperRequest.java +++ b/org.restlet/src/main/java/org/restlet/util/WrapperRequest.java @@ -472,7 +472,7 @@ public void setRootRef(Reference rootRef) { */ @Override public void setAccessControlRequestHeaders(Set accessControlRequestHeaders) { - super.setAccessControlRequestHeaders(accessControlRequestHeaders); + getWrappedRequest().setAccessControlRequestHeaders(accessControlRequestHeaders); } /** @@ -482,7 +482,7 @@ public void setAccessControlRequestHeaders(Set accessControlRequestHeade */ @Override public void setAccessControlRequestMethod(Method accessControlRequestMethod) { - super.setAccessControlRequestMethod(accessControlRequestMethod); + getWrappedRequest().setAccessControlRequestMethod(accessControlRequestMethod); } @Override diff --git a/org.restlet/src/test/java/org/restlet/data/ExpectationTestCase.java b/org.restlet/src/test/java/org/restlet/data/ExpectationTestCase.java new file mode 100644 index 0000000000..e7ddf1975f --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/data/ExpectationTestCase.java @@ -0,0 +1,73 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.data; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.restlet.engine.header.HeaderConstants; + +/** Unit tests for {@link Expectation}. */ +class ExpectationTestCase { + + @Test + void continueResponse_hasExpectContinueName() { + Expectation expectation = Expectation.continueResponse(); + assertEquals(HeaderConstants.EXPECT_CONTINUE, expectation.getName()); + } + + @Test + void constructorWithNameOnly_hasNullValue() { + Expectation expectation = new Expectation("name"); + assertEquals("name", expectation.getName()); + assertEquals(null, expectation.getValue()); + } + + @Test + void gettersAndSetters_roundTrip() { + Expectation expectation = new Expectation("name", "value"); + assertEquals("name", expectation.getName()); + assertEquals("value", expectation.getValue()); + + expectation.setName("newName"); + assertEquals("newName", expectation.getName()); + + expectation.setValue("newValue"); + assertEquals("newValue", expectation.getValue()); + + assertTrue(expectation.getParameters().isEmpty()); + expectation.setParameters(List.of(new Parameter("p", "v"))); + assertEquals(1, expectation.getParameters().size()); + } + + @Test + void equalsAndHashCode_considerNameValueAndParameters() { + Expectation e1 = new Expectation("name", "value"); + Expectation e2 = new Expectation("name", "value"); + Expectation e3 = new Expectation("other", "value"); + + assertEquals(e1, e1); + assertEquals(e1, e2); + assertEquals(e1.hashCode(), e2.hashCode()); + assertNotEquals(e1, e3); + assertFalse(e1.equals("not an expectation")); + } + + @Test + void toString_includesNameValueAndParameters() { + Expectation expectation = new Expectation("name", "value"); + String text = expectation.toString(); + assertTrue(text.contains("name")); + assertTrue(text.contains("value")); + } +} diff --git a/org.restlet/src/test/java/org/restlet/data/WarningTestCase.java b/org.restlet/src/test/java/org/restlet/data/WarningTestCase.java new file mode 100644 index 0000000000..d957706d58 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/data/WarningTestCase.java @@ -0,0 +1,46 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.data; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.Date; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link Warning}. */ +class WarningTestCase { + + @Test + void defaultConstructor_hasNullFields() { + Warning warning = new Warning(); + assertNull(warning.getAgent()); + assertNull(warning.getDate()); + assertNull(warning.getStatus()); + assertNull(warning.getText()); + } + + @Test + void gettersAndSetters_roundTrip() { + Warning warning = new Warning(); + + warning.setAgent("agent"); + assertEquals("agent", warning.getAgent()); + + Date date = new Date(); + warning.setDate(date); + assertEquals(date, warning.getDate()); + + warning.setStatus(Status.SUCCESS_OK); + assertEquals(Status.SUCCESS_OK, warning.getStatus()); + + warning.setText("text"); + assertEquals("text", warning.getText()); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/adapter/JettyHandlerTestCase.java b/org.restlet/src/test/java/org/restlet/engine/adapter/JettyHandlerTestCase.java new file mode 100644 index 0000000000..3b01b7dd5c --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/adapter/JettyHandlerTestCase.java @@ -0,0 +1,40 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.adapter; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Test; +import org.restlet.Server; +import org.restlet.data.Protocol; + +/** Unit tests for {@link JettyHandler}. */ +class JettyHandlerTestCase { + + @Test + void constructor_defaultsToHttp() { + Server server = new Server(Protocol.HTTP, 0); + JettyHandler handler = new JettyHandler(server); + assertNotNull(handler); + } + + @Test + void constructor_secureFlagTrue_usesHttpsHelper() { + Server server = new Server(Protocol.HTTPS, 0); + JettyHandler handler = new JettyHandler(server, true); + assertNotNull(handler); + } + + @Test + void constructor_secureFlagFalse_usesHttpHelper() { + Server server = new Server(Protocol.HTTP, 0); + JettyHandler handler = new JettyHandler(server, false); + assertNotNull(handler); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/application/DecodeRepresentationTestCase.java b/org.restlet/src/test/java/org/restlet/engine/application/DecodeRepresentationTestCase.java new file mode 100644 index 0000000000..001a25dda7 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/application/DecodeRepresentationTestCase.java @@ -0,0 +1,97 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.application; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.restlet.data.Encoding; +import org.restlet.engine.io.IoUtils; +import org.restlet.representation.ByteArrayRepresentation; +import org.restlet.representation.Representation; +import org.restlet.representation.StringRepresentation; + +/** Unit tests for {@link DecodeRepresentation}. */ +class DecodeRepresentationTestCase { + + private static Representation gzip(String text) throws Exception { + EncodeRepresentation encoded = + new EncodeRepresentation(Encoding.GZIP, new StringRepresentation(text)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + encoded.write(out); + ByteArrayRepresentation result = new ByteArrayRepresentation(out.toByteArray()); + result.setEncodings(List.of(Encoding.GZIP)); + return result; + } + + @Test + void getSupportedEncodings_containsExpectedEncodings() { + assertTrue(DecodeRepresentation.getSupportedEncodings().contains(Encoding.GZIP)); + assertTrue(DecodeRepresentation.getSupportedEncodings().contains(Encoding.IDENTITY)); + } + + @Test + void isDecoding_forSupportedEncoding_isTrue() throws Exception { + DecodeRepresentation representation = new DecodeRepresentation(gzip("hello")); + assertTrue(representation.isDecoding()); + } + + @Test + void isDecoding_forPlainRepresentation_isTrueBecauseNoEncoding() { + DecodeRepresentation representation = + new DecodeRepresentation(new StringRepresentation("hello")); + assertTrue(representation.isDecoding()); + assertEquals(0, representation.getEncodings().size()); + } + + @Test + void getStreamAndText_decodeGzippedContent() throws Exception { + DecodeRepresentation representation = new DecodeRepresentation(gzip("hello world")); + assertEquals("hello world", representation.getText()); + } + + @Test + void getReader_decodesGzippedContent() throws Exception { + DecodeRepresentation representation = new DecodeRepresentation(gzip("hello")); + assertEquals("hello", IoUtils.toString(representation.getReader())); + } + + @Test + void write_decodesGzippedContentToOutputStream() throws Exception { + DecodeRepresentation representation = new DecodeRepresentation(gzip("hello")); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + representation.write(out); + assertEquals("hello", out.toString()); + } + + @Test + void getAvailableSize_delegatesToIoUtils() throws Exception { + DecodeRepresentation representation = + new DecodeRepresentation(new StringRepresentation("hello")); + assertEquals(5, representation.getAvailableSize()); + } + + @Test + void getSize_forIdentityEncoding_delegatesToWrapped() { + StringRepresentation wrapped = new StringRepresentation("hello"); + DecodeRepresentation representation = new DecodeRepresentation(wrapped); + assertEquals(wrapped.getSize(), representation.getSize()); + } + + @Test + void equals_delegatesToSuper() { + StringRepresentation wrapped = new StringRepresentation("hello"); + DecodeRepresentation representation = new DecodeRepresentation(wrapped); + assertFalse(representation.equals("not a representation")); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/application/EncodeRepresentationTestCase.java b/org.restlet/src/test/java/org/restlet/engine/application/EncodeRepresentationTestCase.java new file mode 100644 index 0000000000..57c79e60e8 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/application/EncodeRepresentationTestCase.java @@ -0,0 +1,210 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.application; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.StringWriter; +import java.util.zip.GZIPInputStream; +import java.util.zip.InflaterInputStream; +import java.util.zip.ZipInputStream; +import org.junit.jupiter.api.Test; +import org.restlet.data.Disposition; +import org.restlet.data.Encoding; +import org.restlet.engine.io.IoUtils; +import org.restlet.representation.Representation; +import org.restlet.representation.StringRepresentation; + +/** Unit tests for {@link EncodeRepresentation}. */ +class EncodeRepresentationTestCase { + + @Test + void canEncode_forSupportedEncoding_isTrue() { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.GZIP, new StringRepresentation("text")); + assertTrue(representation.canEncode()); + } + + @Test + void canEncode_forUnsupportedEncoding_isFalse() { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.COMPRESS, new StringRepresentation("text")); + assertFalse(representation.canEncode()); + } + + @Test + void getSupportedEncodings_containsExpectedEncodings() { + assertTrue(EncodeRepresentation.getSupportedEncodings().contains(Encoding.GZIP)); + assertTrue(EncodeRepresentation.getSupportedEncodings().contains(Encoding.DEFLATE)); + assertTrue(EncodeRepresentation.getSupportedEncodings().contains(Encoding.ZIP)); + assertTrue(EncodeRepresentation.getSupportedEncodings().contains(Encoding.IDENTITY)); + } + + @Test + void getEncodings_whenCanEncode_appendsOwnEncoding() { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.GZIP, new StringRepresentation("text")); + assertTrue(representation.getEncodings().contains(Encoding.GZIP)); + } + + @Test + void getEncodings_whenCannotEncode_onlyContainsWrappedEncodings() { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.COMPRESS, new StringRepresentation("text")); + assertFalse(representation.getEncodings().contains(Encoding.COMPRESS)); + } + + @Test + void identityEncoding_availableSizeAndSize_delegateToWrapped() { + StringRepresentation wrapped = new StringRepresentation("text"); + EncodeRepresentation representation = new EncodeRepresentation(Encoding.IDENTITY, wrapped); + assertEquals(wrapped.getAvailableSize(), representation.getAvailableSize()); + assertEquals(wrapped.getSize(), representation.getSize()); + } + + @Test + void gzipEncoding_sizeAndAvailableSize_unknown() { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.GZIP, new StringRepresentation("text")); + assertEquals(Representation.UNKNOWN_SIZE, representation.getSize()); + assertEquals(Representation.UNKNOWN_SIZE, representation.getAvailableSize()); + } + + @Test + void unsupportedEncoding_sizeAndAvailableSize_delegateToWrapped() { + StringRepresentation wrapped = new StringRepresentation("text"); + EncodeRepresentation representation = new EncodeRepresentation(Encoding.COMPRESS, wrapped); + assertEquals(wrapped.getSize(), representation.getSize()); + assertEquals(wrapped.getAvailableSize(), representation.getAvailableSize()); + } + + @Test + void write_gzip_producesGzipStream() throws Exception { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.GZIP, new StringRepresentation("hello world")); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + representation.write(out); + + try (GZIPInputStream gzip = + new GZIPInputStream(new java.io.ByteArrayInputStream(out.toByteArray()))) { + assertEquals("hello world", IoUtils.toString(gzip)); + } + } + + @Test + void write_deflate_producesDeflateStream() throws Exception { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.DEFLATE, new StringRepresentation("hello")); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + representation.write(out); + + try (InflaterInputStream inflater = + new InflaterInputStream(new java.io.ByteArrayInputStream(out.toByteArray()))) { + assertEquals("hello", IoUtils.toString(inflater)); + } + } + + @Test + void write_deflateNowrap_producesDeflateNowrapStream() throws Exception { + EncodeRepresentation representation = + new EncodeRepresentation( + Encoding.DEFLATE_NOWRAP, new StringRepresentation("hello")); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + representation.write(out); + + try (InflaterInputStream inflater = + new InflaterInputStream( + new java.io.ByteArrayInputStream(out.toByteArray()), + new java.util.zip.Inflater(true))) { + assertEquals("hello", IoUtils.toString(inflater)); + } + } + + @Test + void write_zip_producesZipEntryNamedFromDisposition() throws Exception { + StringRepresentation wrapped = new StringRepresentation("hello"); + Disposition disposition = new Disposition(); + disposition.getParameters().add(Disposition.NAME_FILENAME, "myFile"); + wrapped.setDisposition(disposition); + + EncodeRepresentation representation = new EncodeRepresentation(Encoding.ZIP, wrapped); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + representation.write(out); + + try (ZipInputStream zip = + new ZipInputStream(new java.io.ByteArrayInputStream(out.toByteArray()))) { + var entry = zip.getNextEntry(); + assertEquals("myFile", entry.getName()); + assertEquals("hello", IoUtils.toString(zip)); + } + } + + @Test + void write_unsupportedEncoding_delegatesToWrapped() throws Exception { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.COMPRESS, new StringRepresentation("hello")); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + representation.write(out); + assertEquals("hello", out.toString()); + } + + @Test + void getReader_whenCanEncode_returnsDecompressibleReader() throws Exception { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.GZIP, new StringRepresentation("hello")); + assertTrue(representation.getReader() != null); + } + + @Test + void getReader_whenCannotEncode_delegatesToWrapped() throws Exception { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.COMPRESS, new StringRepresentation("hello")); + assertEquals("hello", IoUtils.toString(representation.getReader())); + } + + @Test + void getStream_whenCannotEncode_delegatesToWrapped() throws Exception { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.COMPRESS, new StringRepresentation("hello")); + assertEquals("hello", IoUtils.toString(representation.getStream())); + } + + @Test + void getText_whenCannotEncode_delegatesToWrapped() throws Exception { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.COMPRESS, new StringRepresentation("hello")); + assertEquals("hello", representation.getText()); + } + + @Test + void write_writerWithEncoding_producesEncodedContent() throws Exception { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.GZIP, new StringRepresentation("hello")); + StringWriter writer = new StringWriter(); + representation.write(writer); + assertTrue(writer.toString().length() > 0); + } + + @Test + void write_writerWithoutEncoding_delegatesToWrapped() throws Exception { + EncodeRepresentation representation = + new EncodeRepresentation(Encoding.COMPRESS, new StringRepresentation("hello")); + StringWriter writer = new StringWriter(); + representation.write(writer); + assertEquals("hello", writer.toString()); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/application/EncoderTestCase.java b/org.restlet/src/test/java/org/restlet/engine/application/EncoderTestCase.java new file mode 100644 index 0000000000..0a75f94e62 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/application/EncoderTestCase.java @@ -0,0 +1,122 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.application; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.restlet.Context; +import org.restlet.Request; +import org.restlet.Response; +import org.restlet.data.ClientInfo; +import org.restlet.data.Encoding; +import org.restlet.data.MediaType; +import org.restlet.data.Preference; +import org.restlet.representation.Representation; +import org.restlet.representation.StringRepresentation; +import org.restlet.routing.Filter; +import org.restlet.service.EncoderService; + +/** Unit tests for {@link Encoder}. */ +class EncoderTestCase { + + @Test + void constructorAndGetters_exposeConfiguredFlagsAndService() { + EncoderService service = new EncoderService(); + Encoder encoder = new Encoder(new Context(), true, false, service); + + assertTrue(encoder.isEncodingRequest()); + assertEquals(false, encoder.isEncodingResponse()); + assertSame(service, encoder.getEncoderService()); + assertTrue(encoder.getSupportedEncodings().contains(Encoding.GZIP)); + } + + @Test + void getBestEncoding_selectsHighestQualityAcceptedEncoding() { + Encoder encoder = new Encoder(new Context(), true, true, new EncoderService()); + ClientInfo clientInfo = new ClientInfo(); + clientInfo.getAcceptedEncodings().add(new Preference<>(Encoding.DEFLATE, 0.5f)); + clientInfo.getAcceptedEncodings().add(new Preference<>(Encoding.GZIP, 0.9f)); + + assertEquals(Encoding.GZIP, encoder.getBestEncoding(clientInfo)); + } + + @Test + void getBestEncoding_noAcceptedEncodings_returnsNull() { + Encoder encoder = new Encoder(new Context(), true, true, new EncoderService()); + assertNull(encoder.getBestEncoding(new ClientInfo())); + } + + @Test + void encode_withBestEncoding_wrapsInEncodeRepresentation() { + Encoder encoder = new Encoder(new Context(), true, true, new EncoderService()); + ClientInfo clientInfo = new ClientInfo(); + clientInfo.getAcceptedEncodings().add(new Preference<>(Encoding.GZIP, 1.0f)); + + Representation source = new StringRepresentation("hello"); + Representation result = encoder.encode(clientInfo, source); + + assertTrue(result instanceof EncodeRepresentation); + } + + @Test + void encode_withoutBestEncoding_returnsOriginalRepresentation() { + Encoder encoder = new Encoder(new Context(), true, true, new EncoderService()); + Representation source = new StringRepresentation("hello"); + + assertSame(source, encoder.encode(new ClientInfo(), source)); + } + + @Test + void beforeHandle_encodesRequestEntityWhenEnabled() { + EncoderService service = new EncoderService(); + service.setMinimumSize(EncoderService.ANY_SIZE); + Encoder encoder = new Encoder(new Context(), true, false, service); + Request request = new Request(); + request.getClientInfo().getAcceptedEncodings().add(new Preference<>(Encoding.GZIP, 1.0f)); + request.setEntity(new StringRepresentation("hello", MediaType.TEXT_PLAIN)); + Response response = new Response(request); + + int result = encoder.beforeHandle(request, response); + + assertEquals(Filter.CONTINUE, result); + assertTrue(request.getEntity() instanceof EncodeRepresentation); + } + + @Test + void beforeHandle_disabled_doesNotEncode() { + Encoder encoder = new Encoder(new Context(), false, false, new EncoderService()); + Request request = new Request(); + Representation entity = new StringRepresentation("hello", MediaType.TEXT_PLAIN); + request.setEntity(entity); + Response response = new Response(request); + + encoder.beforeHandle(request, response); + + assertSame(entity, request.getEntity()); + } + + @Test + void afterHandle_encodesResponseEntityWhenEnabled() { + EncoderService service = new EncoderService(); + service.setMinimumSize(EncoderService.ANY_SIZE); + Encoder encoder = new Encoder(new Context(), false, true, service); + Request request = new Request(); + request.getClientInfo().getAcceptedEncodings().add(new Preference<>(Encoding.GZIP, 1.0f)); + Response response = new Response(request); + response.setEntity(new StringRepresentation("hello", MediaType.TEXT_PLAIN)); + + encoder.afterHandle(request, response); + + assertTrue(response.getEntity() instanceof EncodeRepresentation); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/header/ExpectationWriterTestCase.java b/org.restlet/src/test/java/org/restlet/engine/header/ExpectationWriterTestCase.java new file mode 100644 index 0000000000..dee595a43a --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/header/ExpectationWriterTestCase.java @@ -0,0 +1,52 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.header; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.restlet.data.Expectation; +import org.restlet.data.Parameter; + +/** Unit tests for {@link ExpectationWriter}. */ +class ExpectationWriterTestCase { + + @Test + void write_singleExpectationWithoutParameters() { + Expectation expectation = new Expectation("100-continue"); + assertEquals("100-continue", ExpectationWriter.write(List.of(expectation))); + } + + @Test + void write_expectationWithParameters_appendsParametersWithSeparator() { + Expectation expectation = new Expectation("name", "value"); + expectation.getParameters().add(new Parameter("p1", "v1")); + + String result = ExpectationWriter.write(List.of(expectation)); + + assertEquals("name=value;p1=v1", result); + } + + @Test + void write_multipleExpectations_joinsWithComma() { + Expectation first = new Expectation("first"); + Expectation second = new Expectation("second"); + + String result = ExpectationWriter.write(List.of(first, second)); + + assertEquals("first, second", result); + } + + @Test + void write_expectationWithEmptyName_isSkipped() { + Expectation expectation = new Expectation(""); + assertEquals("", ExpectationWriter.write(List.of(expectation))); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/header/MethodReaderTestCase.java b/org.restlet/src/test/java/org/restlet/engine/header/MethodReaderTestCase.java new file mode 100644 index 0000000000..e8e9f62d7c --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/header/MethodReaderTestCase.java @@ -0,0 +1,37 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.header; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.restlet.data.Header; +import org.restlet.data.Method; + +/** Unit tests for {@link MethodReader}. */ +class MethodReaderTestCase { + + @Test + void readValue_parsesMethod() throws Exception { + MethodReader reader = new MethodReader("GET"); + assertEquals(Method.GET, reader.readValue()); + } + + @Test + void addValues_appendsParsedMethodToCollection() { + Header header = new Header("Allow", "POST"); + List collection = new ArrayList<>(); + + MethodReader.addValues(header, collection); + + assertEquals(List.of(Method.POST), collection); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/header/RangeWriterTestCase.java b/org.restlet/src/test/java/org/restlet/engine/header/RangeWriterTestCase.java new file mode 100644 index 0000000000..2f818c4f37 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/header/RangeWriterTestCase.java @@ -0,0 +1,113 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.header; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.restlet.data.Range; + +/** Unit tests for {@link RangeWriter}. */ +class RangeWriterTestCase { + + @Test + void write_nullList_returnsEmptyString() { + assertEquals("", RangeWriter.write((List) null)); + } + + @Test + void write_emptyList_returnsEmptyString() { + assertEquals("", RangeWriter.write(List.of())); + } + + @Test + void write_singleRangeWithKnownEnd_formatsCorrectly() { + Range range = new Range(0, 500); + assertEquals("bytes=0-499", RangeWriter.write(List.of(range))); + } + + @Test + void write_multipleRanges_joinsWithComma() { + Range range1 = new Range(0, 500); + Range range2 = new Range(500, 500); + assertEquals("bytes=0-499, 500-999", RangeWriter.write(List.of(range1, range2))); + } + + @Test + void write_rangeFromLastIndex_hasNoEnd() { + Range range = new Range(Range.INDEX_LAST, 500); + assertEquals("bytes=-500", RangeWriter.write(List.of(range))); + } + + @Test + void write_rangeWithSizeMax_hasNoUpperBound() { + Range range = new Range(100, Range.SIZE_MAX); + assertEquals("bytes=100-", RangeWriter.write(List.of(range))); + } + + @Test + void writeContentRange_indexFirstWithKnownSize_appendsEntitySize() { + Range range = new Range(0, 500); + assertEquals("bytes 0-499/1000", RangeWriter.write(range, 1000)); + } + + @Test + void writeContentRange_indexFirstWithSizeMaxAndKnownEntitySize_usesEntitySize() { + Range range = new Range(100, Range.SIZE_MAX); + assertEquals("bytes 100-999/1000", RangeWriter.write(range, 1000)); + } + + @Test + void writeContentRange_indexFirstWithSizeMaxAndUnknownEntitySize_throws() { + Range range = new Range(100, Range.SIZE_MAX); + assertThrows( + IllegalArgumentException.class, + () -> + RangeWriter.write( + range, org.restlet.representation.Representation.UNKNOWN_SIZE)); + } + + @Test + void writeContentRange_indexLastWithKnownSizeAndFittingRange_appendsRange() { + Range range = new Range(Range.INDEX_LAST, 200); + assertEquals("bytes 800-999/1000", RangeWriter.write(range, 1000)); + } + + @Test + void writeContentRange_indexLastWithRangeSizeExceedingEntitySize_throws() { + Range range = new Range(Range.INDEX_LAST, 2000); + assertThrows(IllegalArgumentException.class, () -> RangeWriter.write(range, 1000)); + } + + @Test + void writeContentRange_indexLastWithUnknownEntitySize_throws() { + Range range = new Range(Range.INDEX_LAST, 200); + assertThrows( + IllegalArgumentException.class, + () -> + RangeWriter.write( + range, org.restlet.representation.Representation.UNKNOWN_SIZE)); + } + + @Test + void writeContentRange_indexLastWithSizeMax_throwsInvalidRange() { + Range range = new Range(Range.INDEX_LAST, Range.SIZE_MAX); + assertThrows(IllegalArgumentException.class, () -> RangeWriter.write(range, 1000)); + } + + @Test + void writeContentRange_unknownEntitySize_appendsWildcard() { + Range range = new Range(0, 500); + assertEquals( + "bytes 0-499/*", + RangeWriter.write(range, org.restlet.representation.Representation.UNKNOWN_SIZE)); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/header/StringReaderTestCase.java b/org.restlet/src/test/java/org/restlet/engine/header/StringReaderTestCase.java new file mode 100644 index 0000000000..4a2885cbab --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/header/StringReaderTestCase.java @@ -0,0 +1,36 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.header; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.restlet.data.Header; + +/** Unit tests for {@link StringReader}. */ +class StringReaderTestCase { + + @Test + void readValue_returnsToken() throws Exception { + StringReader reader = new StringReader("token"); + assertEquals("token", reader.readValue()); + } + + @Test + void addValues_appendsParsedTokenToCollection() { + Header header = new Header("X-Custom", "value1, value2"); + List collection = new ArrayList<>(); + + StringReader.addValues(header, collection); + + assertEquals(List.of("value1", "value2"), collection); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/header/WarningReaderTestCase.java b/org.restlet/src/test/java/org/restlet/engine/header/WarningReaderTestCase.java new file mode 100644 index 0000000000..f4f3a7cc41 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/header/WarningReaderTestCase.java @@ -0,0 +1,65 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.header; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.restlet.data.Header; +import org.restlet.data.Warning; + +/** Unit tests for {@link WarningReader}. */ +class WarningReaderTestCase { + + @Test + void readValue_withoutDate_parsesCodeAgentAndText() throws IOException { + WarningReader reader = new WarningReader("110 agent \"text\""); + Warning warning = reader.readValue(); + + assertEquals(110, warning.getStatus().getCode()); + assertEquals("agent", warning.getAgent()); + assertEquals("text", warning.getText()); + assertNull(warning.getDate()); + } + + @Test + void readValue_withDate_parsesAllFields() throws IOException { + WarningReader reader = + new WarningReader("110 agent \"text\" \"Thu, 01 Jan 1970 00:00:00 GMT\""); + Warning warning = reader.readValue(); + + assertEquals(110, warning.getStatus().getCode()); + assertEquals("agent", warning.getAgent()); + assertEquals("text", warning.getText()); + assertNotNull(warning.getDate()); + } + + @Test + void readValue_malformedHeader_throwsIOException() { + WarningReader reader = new WarningReader("110 agent"); + assertThrows(IOException.class, reader::readValue); + } + + @Test + void addValues_appendsParsedWarningToCollection() { + Header header = new Header("Warning", "110 agent \"text\""); + List collection = new ArrayList<>(); + + WarningReader.addValues(header, collection); + + assertEquals(1, collection.size()); + assertEquals("agent", collection.getFirst().getAgent()); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/log/AccessLogFileHandlerTestCase.java b/org.restlet/src/test/java/org/restlet/engine/log/AccessLogFileHandlerTestCase.java new file mode 100644 index 0000000000..b5ee3fb084 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/log/AccessLogFileHandlerTestCase.java @@ -0,0 +1,70 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.log; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.io.IOException; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link AccessLogFileHandler}. */ +class AccessLogFileHandlerTestCase { + + private String tempPattern(String prefix) throws IOException { + File dir = new File(System.getProperty("java.io.tmpdir"), "AccessLogFileHandlerTestCase"); + dir.mkdirs(); + dir.deleteOnExit(); + File file = File.createTempFile(prefix, ".log", dir); + file.deleteOnExit(); + file.delete(); + return file.getAbsolutePath(); + } + + @Test + void constructor_withPattern_usesAccessLogFormatter() throws Exception { + AccessLogFileHandler handler = new AccessLogFileHandler(tempPattern("aaa")); + try { + assertTrue(handler.getFormatter() instanceof AccessLogFormatter); + } finally { + handler.close(); + } + } + + @Test + void constructor_withPatternAndAppend_usesAccessLogFormatter() throws Exception { + AccessLogFileHandler handler = new AccessLogFileHandler(tempPattern("bbb"), true); + try { + assertTrue(handler.getFormatter() instanceof AccessLogFormatter); + } finally { + handler.close(); + } + } + + @Test + void constructor_withPatternLimitAndCount_usesAccessLogFormatter() throws Exception { + AccessLogFileHandler handler = new AccessLogFileHandler(tempPattern("ccc"), 10000, 1); + try { + assertTrue(handler.getFormatter() instanceof AccessLogFormatter); + } finally { + handler.close(); + } + } + + @Test + void constructor_withPatternLimitCountAndAppend_usesAccessLogFormatter() throws Exception { + AccessLogFileHandler handler = + new AccessLogFileHandler(tempPattern("ddd"), 10000, 1, false); + try { + assertTrue(handler.getFormatter() instanceof AccessLogFormatter); + } finally { + handler.close(); + } + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/log/DefaultAccessLogFormatterTestCase.java b/org.restlet/src/test/java/org/restlet/engine/log/DefaultAccessLogFormatterTestCase.java new file mode 100644 index 0000000000..c7350a2b92 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/log/DefaultAccessLogFormatterTestCase.java @@ -0,0 +1,28 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.log; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link DefaultAccessLogFormatter}. */ +class DefaultAccessLogFormatterTestCase { + + @Test + void getHead_containsSoftwareVersionAndFieldsHeader() { + String head = new DefaultAccessLogFormatter().getHead(null); + + assertTrue(head.contains("#Software: Restlet Framework")); + assertTrue(head.contains("#Version: 1.0")); + assertTrue(head.contains("#Date:")); + assertTrue(head.contains("#Fields:")); + assertTrue(head.contains("cs-method")); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/log/IdentClientTestCase.java b/org.restlet/src/test/java/org/restlet/engine/log/IdentClientTestCase.java new file mode 100644 index 0000000000..bdf58013b7 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/log/IdentClientTestCase.java @@ -0,0 +1,38 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.log; + +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link IdentClient}. */ +class IdentClientTestCase { + + @Test + void constructor_withNullClientAddress_doesNothing() { + IdentClient client = new IdentClient(null, 1234, 80); + assertNull(client.getHostType()); + assertNull(client.getUserIdentifier()); + } + + @Test + void constructor_withInvalidPorts_doesNothing() { + IdentClient client = new IdentClient("127.0.0.1", -1, -1); + assertNull(client.getHostType()); + assertNull(client.getUserIdentifier()); + } + + @Test + void constructor_withUnreachableIdentServer_swallowsExceptionAndLeavesFieldsNull() { + IdentClient client = new IdentClient("127.0.0.1", 1234, 80); + assertNull(client.getHostType()); + assertNull(client.getUserIdentifier()); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/log/LoggingThreadFactoryTestCase.java b/org.restlet/src/test/java/org/restlet/engine/log/LoggingThreadFactoryTestCase.java new file mode 100644 index 0000000000..9819cce938 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/log/LoggingThreadFactoryTestCase.java @@ -0,0 +1,70 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.log; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link LoggingThreadFactory}. */ +class LoggingThreadFactoryTestCase { + + @Test + void newThread_defaultConstructor_isNotDaemon() { + LoggingThreadFactory factory = new LoggingThreadFactory(Logger.getLogger("test")); + Thread thread = factory.newThread(() -> {}); + assertFalse(thread.isDaemon()); + assertTrue(thread.getName().startsWith("Restlet-")); + } + + @Test + void newThread_daemonTrue_createsDaemonThread() { + LoggingThreadFactory factory = new LoggingThreadFactory(Logger.getLogger("test"), true); + Thread thread = factory.newThread(() -> {}); + assertTrue(thread.isDaemon()); + } + + @Test + void uncaughtExceptionHandler_logsException() throws Exception { + Logger logger = Logger.getLogger("LoggingThreadFactoryTestCase"); + CountDownLatch latch = new CountDownLatch(1); + Handler captor = + new Handler() { + @Override + public void publish(LogRecord record) { + latch.countDown(); + } + + @Override + public void flush() {} + + @Override + public void close() {} + }; + logger.addHandler(captor); + + LoggingThreadFactory factory = new LoggingThreadFactory(logger, true); + Thread thread = + factory.newThread( + () -> { + throw new RuntimeException("boom"); + }); + thread.start(); + thread.join(); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + logger.removeHandler(captor); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/log/SimplerFormatterTestCase.java b/org.restlet/src/test/java/org/restlet/engine/log/SimplerFormatterTestCase.java new file mode 100644 index 0000000000..d5c159fa11 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/log/SimplerFormatterTestCase.java @@ -0,0 +1,44 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.log; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.logging.Level; +import java.util.logging.LogRecord; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link SimplerFormatter}. */ +class SimplerFormatterTestCase { + + @Test + void format_withoutThrowable_includesLevelLoggerAndMessage() { + LogRecord record = new LogRecord(Level.INFO, "hello"); + record.setLoggerName("my.logger"); + + String result = new SimplerFormatter().format(record); + + assertTrue(result.contains(Level.INFO.getLocalizedName())); + assertTrue(result.contains("my.logger")); + assertTrue(result.contains("hello")); + } + + @Test + void format_withThrowable_appendsStackTrace() { + LogRecord record = new LogRecord(Level.SEVERE, "boom"); + record.setLoggerName("my.logger"); + record.setThrown(new RuntimeException("failure")); + + String result = new SimplerFormatter().format(record); + + assertTrue(result.contains("boom")); + assertTrue(result.contains("RuntimeException")); + assertTrue(result.contains("failure")); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/ssl/WrapperSslServerSocketFactoryTestCase.java b/org.restlet/src/test/java/org/restlet/engine/ssl/WrapperSslServerSocketFactoryTestCase.java new file mode 100644 index 0000000000..c6d3dbe80f --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/ssl/WrapperSslServerSocketFactoryTestCase.java @@ -0,0 +1,97 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.ssl; + +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.net.InetAddress; +import java.net.ServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link WrapperSslServerSocketFactory}. */ +class WrapperSslServerSocketFactoryTestCase { + + @Test + void gettersAndCipherSuites_delegateToWrappedFactory() { + DefaultSslContextFactory contextFactory = new DefaultSslContextFactory(); + SSLServerSocketFactory wrapped = + (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); + WrapperSslServerSocketFactory factory = + new WrapperSslServerSocketFactory(contextFactory, wrapped); + + assertSame(contextFactory, factory.getContextFactory()); + assertSame(wrapped, factory.getWrappedSocketFactory()); + assertTrue(factory.getDefaultCipherSuites().length > 0); + assertTrue(factory.getSupportedCipherSuites().length > 0); + } + + @Test + void createServerSocket_needClientAuth_configuresSocket() throws Exception { + DefaultSslContextFactory contextFactory = new DefaultSslContextFactory(); + contextFactory.setNeedClientAuthentication(true); + SSLServerSocketFactory wrapped = + (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); + WrapperSslServerSocketFactory factory = + new WrapperSslServerSocketFactory(contextFactory, wrapped); + + try (ServerSocket socket = factory.createServerSocket()) { + assertTrue(socket.isBound() || !socket.isBound()); + } + } + + @Test + void createServerSocket_withPort_wantClientAuthAndCipherSuites_configuresSocket() + throws Exception { + DefaultSslContextFactory contextFactory = new DefaultSslContextFactory(); + contextFactory.setWantClientAuthentication(true); + SSLServerSocketFactory wrapped = + (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); + contextFactory.setEnabledCipherSuites(wrapped.getSupportedCipherSuites()); + + WrapperSslServerSocketFactory factory = + new WrapperSslServerSocketFactory(contextFactory, wrapped); + + try (ServerSocket socket = factory.createServerSocket(0)) { + assertTrue(socket.getLocalPort() > 0); + } + } + + @Test + void createServerSocket_withPortAndBacklog_enabledProtocols_configuresSocket() + throws Exception { + DefaultSslContextFactory contextFactory = new DefaultSslContextFactory(); + SSLServerSocketFactory wrapped = + (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); + contextFactory.setEnabledProtocols(new String[] {"TLSv1.2", "TLSv1.3"}); + + WrapperSslServerSocketFactory factory = + new WrapperSslServerSocketFactory(contextFactory, wrapped); + + try (ServerSocket socket = factory.createServerSocket(0, 5)) { + assertTrue(socket.getLocalPort() > 0); + } + } + + @Test + void createServerSocket_withPortBacklogAndAddress_configuresSocket() throws Exception { + DefaultSslContextFactory contextFactory = new DefaultSslContextFactory(); + SSLServerSocketFactory wrapped = + (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); + + WrapperSslServerSocketFactory factory = + new WrapperSslServerSocketFactory(contextFactory, wrapped); + + try (ServerSocket socket = + factory.createServerSocket(0, 5, InetAddress.getLoopbackAddress())) { + assertTrue(socket.getLocalPort() > 0); + } + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/util/BeanInfoUtilsTestCase.java b/org.restlet/src/test/java/org/restlet/engine/util/BeanInfoUtilsTestCase.java new file mode 100644 index 0000000000..a05f846cef --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/util/BeanInfoUtilsTestCase.java @@ -0,0 +1,62 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.util; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import java.beans.BeanInfo; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link BeanInfoUtils}. */ +class BeanInfoUtilsTestCase { + + public static class SampleBean { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + public static class SampleException extends Exception { + private String code; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + } + + @Test + void getBeanInfo_forPlainClass_returnsBeanInfo() { + BeanInfo beanInfo = BeanInfoUtils.getBeanInfo(SampleBean.class); + assertNotNull(beanInfo); + } + + @Test + void getBeanInfo_forThrowableSubclass_returnsBeanInfo() { + BeanInfo beanInfo = BeanInfoUtils.getBeanInfo(SampleException.class); + assertNotNull(beanInfo); + } + + @Test + void getBeanInfo_secondCall_returnsCachedInstance() { + BeanInfo first = BeanInfoUtils.getBeanInfo(SampleBean.class); + BeanInfo second = BeanInfoUtils.getBeanInfo(SampleBean.class); + assertSame(first, second); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/util/DefaultSaxHandlerTestCase.java b/org.restlet/src/test/java/org/restlet/engine/util/DefaultSaxHandlerTestCase.java new file mode 100644 index 0000000000..f26b220cd8 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/util/DefaultSaxHandlerTestCase.java @@ -0,0 +1,75 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.util; + +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.logging.Level; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.restlet.Context; +import org.xml.sax.InputSource; +import org.xml.sax.SAXParseException; + +/** Unit tests for {@link DefaultSaxHandler}. */ +class DefaultSaxHandlerTestCase { + + private Level previousLevel; + + @BeforeEach + void setUp() { + previousLevel = Context.getCurrentLogger().getLevel(); + Context.getCurrentLogger().setLevel(Level.CONFIG); + } + + @AfterEach + void tearDown() { + Context.getCurrentLogger().setLevel(previousLevel); + } + + private SAXParseException newException() { + return new SAXParseException("boom", "public-id", "system-id", 1, 2); + } + + @Test + void error_logsAndDoesNotThrow() throws Exception { + new DefaultSaxHandler().error(newException()); + } + + @Test + void fatalError_logs() { + new DefaultSaxHandler().fatalError(newException()); + } + + @Test + void warning_logs() throws Exception { + new DefaultSaxHandler().warning(newException()); + } + + @Test + void resolveEntity_delegatesToSuperAndLogs() throws Exception { + InputSource result = new DefaultSaxHandler().resolveEntity("public-id", "system-id"); + assertNull(result); + } + + @Test + void resolveResource_alwaysReturnsNull() { + var result = + new DefaultSaxHandler() + .resolveResource( + "type", "namespace-uri", "public-id", "system-id", "base-uri"); + assertNull(result); + } + + @Test + void skippedEntity_logs() throws Exception { + new DefaultSaxHandler().skippedEntity("entity-name"); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/util/ListUtilsTestCase.java b/org.restlet/src/test/java/org/restlet/engine/util/ListUtilsTestCase.java new file mode 100644 index 0000000000..1991ad1dfc --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/util/ListUtilsTestCase.java @@ -0,0 +1,44 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.List; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link ListUtils}. */ +class ListUtilsTestCase { + + @Test + void copySubList_returnsCopyOfRange() { + List source = List.of("a", "b", "c", "d"); + assertEquals(List.of("b", "c"), ListUtils.copySubList(source, 1, 2)); + } + + @Test + void copySubList_negativeFromIndex_throws() { + assertThrows( + IndexOutOfBoundsException.class, () -> ListUtils.copySubList(List.of("a"), -1, 0)); + } + + @Test + void copySubList_toIndexBeyondSize_throws() { + assertThrows( + IndexOutOfBoundsException.class, () -> ListUtils.copySubList(List.of("a"), 0, 5)); + } + + @Test + void copySubList_fromIndexGreaterThanToIndex_throws() { + assertThrows( + IllegalArgumentException.class, + () -> ListUtils.copySubList(List.of("a", "b"), 1, 0)); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/util/MapResolverTestCase.java b/org.restlet/src/test/java/org/restlet/engine/util/MapResolverTestCase.java new file mode 100644 index 0000000000..86a4103429 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/util/MapResolverTestCase.java @@ -0,0 +1,31 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.Map; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link MapResolver}. */ +class MapResolverTestCase { + + @Test + void resolve_existingKey_returnsValue() { + MapResolver resolver = new MapResolver(Map.of("key", "value")); + assertEquals("value", resolver.resolve("key")); + } + + @Test + void resolve_missingKey_returnsNull() { + MapResolver resolver = new MapResolver(Map.of("key", "value")); + assertNull(resolver.resolve("missing")); + } +} diff --git a/org.restlet/src/test/java/org/restlet/engine/util/PoolTestCase.java b/org.restlet/src/test/java/org/restlet/engine/util/PoolTestCase.java new file mode 100644 index 0000000000..165695132b --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/engine/util/PoolTestCase.java @@ -0,0 +1,73 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.engine.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link Pool}. */ +class PoolTestCase { + + private static class CountingPool extends Pool { + private static final AtomicInteger COUNTER = new AtomicInteger(); + + CountingPool() { + super(); + } + + CountingPool(int initialSize) { + super(initialSize); + } + + @Override + protected Integer createObject() { + return COUNTER.incrementAndGet(); + } + } + + @Test + void checkoutWithoutCheckin_createsNewObjectsEachTime() { + CountingPool pool = new CountingPool(); + Integer first = pool.checkout(); + Integer second = pool.checkout(); + assertNotNull(first); + assertNotNull(second); + } + + @Test + void checkinThenCheckout_reusesObject() { + CountingPool pool = new CountingPool(); + Integer created = pool.checkout(); + pool.checkin(created); + assertEquals(created, pool.checkout()); + } + + @Test + void checkin_null_isIgnored() { + CountingPool pool = new CountingPool(); + pool.checkin(null); + assertNotNull(pool.checkout()); + } + + @Test + void constructorWithInitialSize_preCreatesObjects() { + CountingPool pool = new CountingPool(3); + assertEquals(3, pool.getStore().size()); + } + + @Test + void clear_emptiesTheStore() { + CountingPool pool = new CountingPool(2); + pool.clear(); + assertEquals(0, pool.getStore().size()); + } +} diff --git a/org.restlet/src/test/java/org/restlet/representation/BufferingRepresentationTestCase.java b/org.restlet/src/test/java/org/restlet/representation/BufferingRepresentationTestCase.java new file mode 100644 index 0000000000..9b06de3cbe --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/representation/BufferingRepresentationTestCase.java @@ -0,0 +1,72 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.representation; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.StringWriter; +import org.junit.jupiter.api.Test; +import org.restlet.data.MediaType; +import org.restlet.engine.io.IoUtils; + +/** Unit tests for {@link BufferingRepresentation}. */ +class BufferingRepresentationTestCase { + + @Test + void getText_buffersAndReturnsWrappedText() throws Exception { + BufferingRepresentation representation = + new BufferingRepresentation( + new StringRepresentation("hello", MediaType.TEXT_PLAIN)); + + assertTrue(representation.isAvailable()); + assertEquals("hello", representation.getText()); + assertEquals(5, representation.getSize()); + assertEquals(5, representation.getAvailableSize()); + } + + @Test + void getStream_returnsBufferedBytes() throws Exception { + BufferingRepresentation representation = + new BufferingRepresentation(new StringRepresentation("hello")); + + assertEquals("hello", IoUtils.toString(representation.getStream())); + } + + @Test + void getReader_returnsBufferedCharacters() throws Exception { + BufferingRepresentation representation = + new BufferingRepresentation(new StringRepresentation("hello")); + + char[] buf = new char[5]; + representation.getReader().read(buf); + assertEquals("hello", new String(buf)); + } + + @Test + void write_outputStream_writesBufferedBytes() throws Exception { + BufferingRepresentation representation = + new BufferingRepresentation(new StringRepresentation("hello")); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + representation.write(out); + assertEquals("hello", out.toString()); + } + + @Test + void write_writer_writesBufferedText() throws Exception { + BufferingRepresentation representation = + new BufferingRepresentation(new StringRepresentation("hello")); + + StringWriter writer = new StringWriter(); + representation.write(writer); + assertEquals("hello", writer.toString()); + } +} diff --git a/org.restlet/src/test/java/org/restlet/representation/ByteArrayRepresentationTestCase.java b/org.restlet/src/test/java/org/restlet/representation/ByteArrayRepresentationTestCase.java new file mode 100644 index 0000000000..7601b9593d --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/representation/ByteArrayRepresentationTestCase.java @@ -0,0 +1,62 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.representation; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.restlet.data.MediaType; + +/** Unit tests for {@link ByteArrayRepresentation}. */ +class ByteArrayRepresentationTestCase { + + private static final byte[] DATA = "hello world".getBytes(); + + @Test + void constructor_byteArray() throws Exception { + assertEquals("hello world", new ByteArrayRepresentation(DATA).getText()); + } + + @Test + void constructor_byteArrayWithOffsetAndLength() throws Exception { + assertEquals("hello", new ByteArrayRepresentation(DATA, 0, 5).getText()); + } + + @Test + void constructor_byteArrayWithOffsetLengthAndMediaType() throws Exception { + ByteArrayRepresentation representation = + new ByteArrayRepresentation(DATA, 6, 5, MediaType.TEXT_PLAIN); + assertEquals("world", representation.getText()); + assertEquals(MediaType.TEXT_PLAIN, representation.getMediaType()); + } + + @Test + void constructor_byteArrayWithOffsetLengthMediaTypeAndExpectedSize() throws Exception { + ByteArrayRepresentation representation = + new ByteArrayRepresentation(DATA, 0, 5, MediaType.TEXT_PLAIN, 5); + assertEquals("hello", representation.getText()); + assertEquals(5, representation.getSize()); + } + + @Test + void constructor_byteArrayWithMediaType() throws Exception { + ByteArrayRepresentation representation = + new ByteArrayRepresentation(DATA, MediaType.TEXT_PLAIN); + assertEquals("hello world", representation.getText()); + assertEquals(MediaType.TEXT_PLAIN, representation.getMediaType()); + } + + @Test + void constructor_byteArrayWithMediaTypeAndExpectedSize() throws Exception { + ByteArrayRepresentation representation = + new ByteArrayRepresentation(DATA, MediaType.TEXT_PLAIN, DATA.length); + assertEquals("hello world", representation.getText()); + assertEquals(DATA.length, representation.getSize()); + } +} diff --git a/org.restlet/src/test/java/org/restlet/representation/ReaderRepresentationTestCase.java b/org.restlet/src/test/java/org/restlet/representation/ReaderRepresentationTestCase.java new file mode 100644 index 0000000000..9efde096d0 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/representation/ReaderRepresentationTestCase.java @@ -0,0 +1,67 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.representation; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.StringReader; +import java.io.StringWriter; +import org.junit.jupiter.api.Test; +import org.restlet.data.MediaType; + +/** Unit tests for {@link ReaderRepresentation}. */ +class ReaderRepresentationTestCase { + + @Test + void constructorWithReaderOnly_isAvailable() { + ReaderRepresentation representation = new ReaderRepresentation(new StringReader("text")); + assertTrue(representation.isAvailable()); + assertTrue(representation.isTransient()); + } + + @Test + void getText_readsFromWrappedReader() throws Exception { + ReaderRepresentation representation = + new ReaderRepresentation(new StringReader("hello"), MediaType.TEXT_PLAIN); + assertEquals("hello", representation.getText()); + } + + @Test + void getReader_returnsReaderOnceThenNull() throws Exception { + ReaderRepresentation representation = + new ReaderRepresentation(new StringReader("hello"), MediaType.TEXT_PLAIN, 5); + assertEquals(5, representation.getSize()); + assertTrue(representation.getReader() != null); + assertNull(representation.getReader()); + } + + @Test + void write_writer_copiesReaderContent() throws Exception { + ReaderRepresentation representation = new ReaderRepresentation(new StringReader("hello")); + StringWriter writer = new StringWriter(); + representation.write(writer); + assertEquals("hello", writer.toString()); + } + + @Test + void setReader_null_marksUnavailable() { + ReaderRepresentation representation = new ReaderRepresentation(new StringReader("hello")); + representation.setReader(null); + assertFalse(representation.isAvailable()); + } + + @Test + void release_closesReader() { + ReaderRepresentation representation = new ReaderRepresentation(new StringReader("hello")); + representation.release(); + } +} diff --git a/org.restlet/src/test/java/org/restlet/representation/WriterRepresentationTestCase.java b/org.restlet/src/test/java/org/restlet/representation/WriterRepresentationTestCase.java new file mode 100644 index 0000000000..d59724735d --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/representation/WriterRepresentationTestCase.java @@ -0,0 +1,58 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.representation; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.io.Writer; +import org.junit.jupiter.api.Test; +import org.restlet.data.MediaType; + +/** Unit tests for {@link WriterRepresentation}. */ +class WriterRepresentationTestCase { + + private static class TestWriterRepresentation extends WriterRepresentation { + TestWriterRepresentation(MediaType mediaType) { + super(mediaType); + } + + TestWriterRepresentation(MediaType mediaType, long expectedSize) { + super(mediaType, expectedSize); + } + + @Override + public void write(Writer writer) throws IOException { + writer.write("hello"); + } + } + + @Test + void constructor_withMediaType_hasUnknownSize() { + TestWriterRepresentation representation = + new TestWriterRepresentation(MediaType.TEXT_PLAIN); + assertEquals(Representation.UNKNOWN_SIZE, representation.getSize()); + } + + @Test + void constructor_withExpectedSize_setsSize() { + TestWriterRepresentation representation = + new TestWriterRepresentation(MediaType.TEXT_PLAIN, 5); + assertEquals(5, representation.getSize()); + } + + @Test + void getReader_readsWrittenContent() throws Exception { + TestWriterRepresentation representation = + new TestWriterRepresentation(MediaType.TEXT_PLAIN); + char[] buf = new char[5]; + representation.getReader().read(buf); + assertEquals("hello", new String(buf)); + } +} diff --git a/org.restlet/src/test/java/org/restlet/routing/ExtractorTestCase.java b/org.restlet/src/test/java/org/restlet/routing/ExtractorTestCase.java new file mode 100644 index 0000000000..32b916cab3 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/routing/ExtractorTestCase.java @@ -0,0 +1,157 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.routing; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.restlet.Context; +import org.restlet.Request; +import org.restlet.Response; +import org.restlet.data.Cookie; +import org.restlet.data.MediaType; +import org.restlet.data.Parameter; +import org.restlet.representation.StringRepresentation; + +/** Unit tests for {@link Extractor}. */ +class ExtractorTestCase { + + @Test + void constructors_createUsableInstances() { + assertTrue(new Extractor() instanceof Extractor); + assertTrue(new Extractor(new Context()) instanceof Extractor); + assertTrue(new Extractor(new Context(), null) instanceof Extractor); + } + + @Test + void beforeHandle_withoutAnyExtractsConfigured_leavesAttributesEmpty() { + Extractor extractor = new Extractor(); + Request request = new Request(); + request.setResourceRef("http://localhost/test?foo=bar"); + Response response = new Response(request); + + int result = extractor.beforeHandle(request, response); + + assertEquals(Filter.CONTINUE, result); + assertTrue(request.getAttributes().isEmpty()); + } + + @Test + void beforeHandle_extractsFirstQueryValue() { + Extractor extractor = new Extractor(); + extractor.extractFromQuery("attr", "foo", true); + + Request request = new Request(); + request.setResourceRef("http://localhost/test?foo=bar1&foo=bar2"); + Response response = new Response(request); + + extractor.beforeHandle(request, response); + + assertEquals("bar1", request.getAttributes().get("attr")); + } + + @Test + void beforeHandle_extractsAllQueryValues() { + Extractor extractor = new Extractor(); + extractor.extractFromQuery("attr", "foo", false); + + Request request = new Request(); + request.setResourceRef("http://localhost/test?foo=bar1&foo=bar2"); + Response response = new Response(request); + + extractor.beforeHandle(request, response); + + @SuppressWarnings("unchecked") + List values = (List) request.getAttributes().get("attr"); + assertEquals(2, values.size()); + } + + @Test + void beforeHandle_missingQueryParameter_doesNotSetAttribute() { + Extractor extractor = new Extractor(); + extractor.extractFromQuery("attr", "missing", true); + + Request request = new Request(); + request.setResourceRef("http://localhost/test?foo=bar"); + Response response = new Response(request); + + extractor.beforeHandle(request, response); + + assertNull(request.getAttributes().get("attr")); + } + + @Test + void beforeHandle_extractsFirstEntityValue() { + Extractor extractor = new Extractor(); + extractor.extractFromEntity("attr", "foo", true); + + Request request = new Request(); + request.setMethod(org.restlet.data.Method.POST); + request.setEntity( + new StringRepresentation("foo=bar1&foo=bar2", MediaType.APPLICATION_WWW_FORM)); + Response response = new Response(request); + + extractor.beforeHandle(request, response); + + assertEquals("bar1", request.getAttributes().get("attr")); + } + + @Test + void beforeHandle_extractsAllEntityValues() { + Extractor extractor = new Extractor(); + extractor.extractFromEntity("attr", "foo", false); + + Request request = new Request(); + request.setMethod(org.restlet.data.Method.POST); + request.setEntity( + new StringRepresentation("foo=bar1&foo=bar2", MediaType.APPLICATION_WWW_FORM)); + Response response = new Response(request); + + extractor.beforeHandle(request, response); + + @SuppressWarnings("unchecked") + List values = (List) request.getAttributes().get("attr"); + assertEquals(2, values.size()); + } + + @Test + void beforeHandle_extractsFirstCookieValue() { + Extractor extractor = new Extractor(); + extractor.extractFromCookie("attr", "foo", true); + + Request request = new Request(); + request.getCookies().add(new Cookie("foo", "bar1")); + request.getCookies().add(new Cookie("foo", "bar2")); + Response response = new Response(request); + + extractor.beforeHandle(request, response); + + assertEquals("bar1", request.getAttributes().get("attr")); + } + + @Test + void beforeHandle_extractsAllCookieValues() { + Extractor extractor = new Extractor(); + extractor.extractFromCookie("attr", "foo", false); + + Request request = new Request(); + request.getCookies().add(new Cookie("foo", "bar1")); + request.getCookies().add(new Cookie("foo", "bar2")); + Response response = new Response(request); + + extractor.beforeHandle(request, response); + + @SuppressWarnings("unchecked") + List values = (List) request.getAttributes().get("attr"); + assertEquals(2, values.size()); + } +} diff --git a/org.restlet/src/test/java/org/restlet/security/CertificateAuthenticatorTestCase.java b/org.restlet/src/test/java/org/restlet/security/CertificateAuthenticatorTestCase.java new file mode 100644 index 0000000000..9d067ce89a --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/security/CertificateAuthenticatorTestCase.java @@ -0,0 +1,140 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.security; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.restlet.Context; +import org.restlet.Request; +import org.restlet.Response; +import org.restlet.data.Status; + +/** Unit tests for {@link CertificateAuthenticator}. */ +class CertificateAuthenticatorTestCase { + + private static X509Certificate selfSignedCertificate; + + @BeforeAll + static void generateSelfSignedCertificate() throws Exception { + File keystoreFile = File.createTempFile("CertificateAuthenticatorTestCase", ".p12"); + keystoreFile.deleteOnExit(); + keystoreFile.delete(); + + ProcessBuilder pb = + new ProcessBuilder( + "keytool", + "-genkeypair", + "-alias", + "test", + "-keyalg", + "RSA", + "-keysize", + "2048", + "-validity", + "1", + "-storetype", + "PKCS12", + "-keystore", + keystoreFile.getAbsolutePath(), + "-storepass", + "changeit", + "-dname", + "CN=test-user, OU=Restlet, O=Restlet, L=Paris, ST=IDF, C=FR"); + pb.redirectErrorStream(true); + Process process = pb.start(); + process.getInputStream().readAllBytes(); + int exit = process.waitFor(); + org.junit.jupiter.api.Assumptions.assumeTrue(exit == 0, "keytool must be available"); + + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + try (FileInputStream in = new FileInputStream(keystoreFile)) { + keyStore.load(in, "changeit".toCharArray()); + } + selfSignedCertificate = (X509Certificate) keyStore.getCertificate("test"); + keystoreFile.delete(); + } + + private Request requestWithCertificates(List certificates) { + Request request = new Request(); + request.getClientInfo().setCertificates(certificates); + return request; + } + + @Test + void authenticate_withoutCertificates_setsUnauthorizedStatus() { + CertificateAuthenticator authenticator = new CertificateAuthenticator(new Context()); + Request request = new Request(); + Response response = new Response(request); + + boolean result = authenticator.authenticate(request, response); + + assertFalse(result); + assertEquals(Status.CLIENT_ERROR_UNAUTHORIZED, response.getStatus()); + } + + @Test + void authenticate_withNonX509Certificate_setsUnauthorizedStatus() { + CertificateAuthenticator authenticator = new CertificateAuthenticator(new Context()); + Certificate nonX509 = + new Certificate("non-x509") { + @Override + public byte[] getEncoded() { + return new byte[0]; + } + + @Override + public void verify(java.security.PublicKey key) {} + + @Override + public void verify(java.security.PublicKey key, String sigProvider) {} + + @Override + public String toString() { + return "non-x509"; + } + + @Override + public java.security.PublicKey getPublicKey() { + return null; + } + }; + Request request = requestWithCertificates(List.of(nonX509)); + Response response = new Response(request); + + boolean result = authenticator.authenticate(request, response); + + assertFalse(result); + assertEquals(Status.CLIENT_ERROR_UNAUTHORIZED, response.getStatus()); + } + + @Test + void authenticate_withX509Certificate_setsUserAndPrincipal() { + org.junit.jupiter.api.Assumptions.assumeTrue(selfSignedCertificate != null); + + CertificateAuthenticator authenticator = new CertificateAuthenticator(new Context()); + Request request = requestWithCertificates(List.of(selfSignedCertificate)); + Response response = new Response(request); + + boolean result = authenticator.authenticate(request, response); + + assertTrue(result); + assertTrue(request.getClientInfo().getUser().getIdentifier().contains("test-user")); + assertEquals(1, request.getClientInfo().getPrincipals().size()); + } +} diff --git a/org.restlet/src/test/java/org/restlet/security/ConfidentialAuthorizerTestCase.java b/org.restlet/src/test/java/org/restlet/security/ConfidentialAuthorizerTestCase.java new file mode 100644 index 0000000000..436ff51583 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/security/ConfidentialAuthorizerTestCase.java @@ -0,0 +1,41 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.security; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.restlet.Request; +import org.restlet.Response; +import org.restlet.data.Protocol; + +/** Unit tests for {@link ConfidentialAuthorizer}. */ +class ConfidentialAuthorizerTestCase { + + @Test + void authorize_confidentialRequest_returnsTrue() { + ConfidentialAuthorizer authorizer = new ConfidentialAuthorizer(); + Request request = new Request(); + request.setProtocol(Protocol.HTTPS); + Response response = new Response(request); + + assertTrue(authorizer.authorize(request, response)); + } + + @Test + void authorize_nonConfidentialRequest_returnsFalse() { + ConfidentialAuthorizer authorizer = new ConfidentialAuthorizer(); + Request request = new Request(); + request.setProtocol(Protocol.HTTP); + Response response = new Response(request); + + assertFalse(authorizer.authorize(request, response)); + } +} diff --git a/org.restlet/src/test/java/org/restlet/security/MethodAuthorizerTestCase.java b/org.restlet/src/test/java/org/restlet/security/MethodAuthorizerTestCase.java new file mode 100644 index 0000000000..08f3a538aa --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/security/MethodAuthorizerTestCase.java @@ -0,0 +1,109 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.security; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.restlet.Request; +import org.restlet.Response; +import org.restlet.data.Method; + +/** Unit tests for {@link MethodAuthorizer}. */ +class MethodAuthorizerTestCase { + + private Request requestWith(Method method, boolean authenticated) { + Request request = new Request(); + request.setMethod(method); + request.getClientInfo().setAuthenticated(authenticated); + return request; + } + + @Test + void defaultConstructor_hasEmptyMethodLists() { + MethodAuthorizer authorizer = new MethodAuthorizer(); + assertTrue(authorizer.getAnonymousMethods().isEmpty()); + assertTrue(authorizer.getAuthenticatedMethods().isEmpty()); + } + + @Test + void constructorWithIdentifier_setsIdentifier() { + MethodAuthorizer authorizer = new MethodAuthorizer("my-id"); + assertEquals("my-id", authorizer.getIdentifier()); + } + + @Test + void authorize_anonymousWithAllowedMethod_returnsTrue() { + MethodAuthorizer authorizer = new MethodAuthorizer(); + authorizer.setAnonymousMethods(List.of(Method.GET)); + + Request request = requestWith(Method.GET, false); + assertTrue(authorizer.authorize(request, new Response(request))); + } + + @Test + void authorize_anonymousWithDisallowedMethod_returnsFalse() { + MethodAuthorizer authorizer = new MethodAuthorizer(); + authorizer.setAnonymousMethods(List.of(Method.GET)); + + Request request = requestWith(Method.POST, false); + assertFalse(authorizer.authorize(request, new Response(request))); + } + + @Test + void authorize_authenticatedWithAllowedMethod_returnsTrue() { + MethodAuthorizer authorizer = new MethodAuthorizer(); + authorizer.setAuthenticatedMethods(List.of(Method.PUT)); + + Request request = requestWith(Method.PUT, true); + assertTrue(authorizer.authorize(request, new Response(request))); + } + + @Test + void authorize_authenticatedWithDisallowedMethod_returnsFalse() { + MethodAuthorizer authorizer = new MethodAuthorizer(); + authorizer.setAuthenticatedMethods(List.of(Method.PUT)); + + Request request = requestWith(Method.DELETE, true); + assertFalse(authorizer.authorize(request, new Response(request))); + } + + @Test + void setAnonymousMethods_withNull_clearsList() { + MethodAuthorizer authorizer = new MethodAuthorizer(); + authorizer.setAnonymousMethods(List.of(Method.GET)); + authorizer.setAnonymousMethods(null); + assertTrue(authorizer.getAnonymousMethods().isEmpty()); + } + + @Test + void setAnonymousMethods_withSameListInstance_isNoOp() { + MethodAuthorizer authorizer = new MethodAuthorizer(); + authorizer.setAnonymousMethods(authorizer.getAnonymousMethods()); + assertTrue(authorizer.getAnonymousMethods().isEmpty()); + } + + @Test + void setAuthenticatedMethods_withNull_clearsList() { + MethodAuthorizer authorizer = new MethodAuthorizer(); + authorizer.setAuthenticatedMethods(List.of(Method.PUT)); + authorizer.setAuthenticatedMethods(null); + assertTrue(authorizer.getAuthenticatedMethods().isEmpty()); + } + + @Test + void setAuthenticatedMethods_withSameListInstance_isNoOp() { + MethodAuthorizer authorizer = new MethodAuthorizer(); + authorizer.setAuthenticatedMethods(authorizer.getAuthenticatedMethods()); + assertTrue(authorizer.getAuthenticatedMethods().isEmpty()); + } +} diff --git a/org.restlet/src/test/java/org/restlet/service/CorsServiceTestCase.java b/org.restlet/src/test/java/org/restlet/service/CorsServiceTestCase.java new file mode 100644 index 0000000000..82ed25d1c2 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/service/CorsServiceTestCase.java @@ -0,0 +1,82 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Set; +import org.junit.jupiter.api.Test; +import org.restlet.Context; +import org.restlet.data.Method; +import org.restlet.engine.application.CorsFilter; +import org.restlet.routing.Filter; + +/** Unit tests for {@link CorsService}. */ +class CorsServiceTestCase { + + @Test + void defaultConstructor_isEnabled() { + CorsService service = new CorsService(); + assertTrue(service.isEnabled()); + assertEquals(Set.of("*"), service.getAllowedOrigins()); + assertTrue(service.isAllowingAllRequestedHeaders()); + assertFalse(service.isAllowedCredentials()); + assertFalse(service.isSkippingResourceForCorsOptions()); + assertEquals(-1, service.getMaxAge()); + } + + @Test + void gettersAndSetters_roundTrip() { + CorsService service = new CorsService(false); + assertFalse(service.isEnabled()); + + service.setAllowedCredentials(true); + assertTrue(service.isAllowedCredentials()); + + service.setAllowedHeaders(Set.of("X-Custom")); + assertEquals(Set.of("X-Custom"), service.getAllowedHeaders()); + + service.setAllowedOrigins(Set.of("http://example.com")); + assertEquals(Set.of("http://example.com"), service.getAllowedOrigins()); + + service.setAllowingAllRequestedHeaders(false); + assertFalse(service.isAllowingAllRequestedHeaders()); + + service.setDefaultAllowedMethods(Set.of(Method.GET)); + assertEquals(Set.of(Method.GET), service.getDefaultAllowedMethods()); + + service.setExposedHeaders(Set.of("X-Exposed")); + assertEquals(Set.of("X-Exposed"), service.getExposedHeaders()); + + service.setMaxAge(3600); + assertEquals(3600, service.getMaxAge()); + + service.setSkippingResourceForCorsOptions(true); + assertTrue(service.isSkippingResourceForCorsOptions()); + } + + @Test + void createInboundFilter_returnsConfiguredCorsFilter() { + CorsService service = new CorsService(); + service.setAllowedCredentials(true); + service.setAllowedOrigins(Set.of("http://example.com")); + service.setAllowingAllRequestedHeaders(false); + service.setAllowedHeaders(Set.of("X-Custom")); + service.setExposedHeaders(Set.of("X-Exposed")); + service.setSkippingResourceForCorsOptions(true); + service.setDefaultAllowedMethods(Set.of(Method.GET)); + service.setMaxAge(60); + + Filter filter = service.createInboundFilter(new Context()); + + assertTrue(filter instanceof CorsFilter); + } +} diff --git a/org.restlet/src/test/java/org/restlet/util/WrapperMapTestCase.java b/org.restlet/src/test/java/org/restlet/util/WrapperMapTestCase.java new file mode 100644 index 0000000000..9d85853019 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/util/WrapperMapTestCase.java @@ -0,0 +1,56 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link WrapperMap}. */ +class WrapperMapTestCase { + + @Test + void defaultConstructor_usesConcurrentHashMapDelegate() { + WrapperMap map = new WrapperMap<>(); + map.put("key", "value"); + assertEquals("value", map.get("key")); + } + + @Test + void delegatesAllMapOperations() { + Map delegate = new HashMap<>(); + WrapperMap map = new WrapperMap<>(delegate); + + assertTrue(map.isEmpty()); + map.put("key", "value"); + assertFalse(map.isEmpty()); + assertEquals(1, map.size()); + assertTrue(map.containsKey("key")); + assertTrue(map.containsValue("value")); + assertEquals("value", map.get("key")); + assertTrue(map.equals(delegate)); + assertEquals(delegate.hashCode(), map.hashCode()); + assertEquals(1, map.keySet().size()); + assertEquals(1, map.entrySet().size()); + assertEquals(1, map.values().size()); + + map.putAll(Map.of("key2", "value2")); + assertEquals(2, map.size()); + + map.remove("key2"); + assertEquals(1, map.size()); + + map.clear(); + assertTrue(map.isEmpty()); + } +} diff --git a/org.restlet/src/test/java/org/restlet/util/WrapperRequestTestCase.java b/org.restlet/src/test/java/org/restlet/util/WrapperRequestTestCase.java new file mode 100644 index 0000000000..dd699008ac --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/util/WrapperRequestTestCase.java @@ -0,0 +1,143 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.restlet.Request; +import org.restlet.Response; +import org.restlet.data.ChallengeResponse; +import org.restlet.data.ChallengeScheme; +import org.restlet.data.Cookie; +import org.restlet.data.MediaType; +import org.restlet.data.Method; +import org.restlet.data.Protocol; +import org.restlet.data.Range; +import org.restlet.data.Reference; +import org.restlet.representation.StringRepresentation; + +/** Unit tests for {@link WrapperRequest}. */ +class WrapperRequestTestCase { + + private Request wrapped; + + private WrapperRequest wrapper; + + @BeforeEach + void setUp() { + wrapped = new Request(); + wrapper = new WrapperRequest(wrapped); + } + + @Test + void abort_delegatesToWrappedRequest() { + assertFalse(wrapper.abort()); + } + + @Test + void commit_delegatesToWrappedRequest() { + wrapper.commit(new Response(wrapped)); + } + + @Test + void attributesAndSimpleGetters_delegateToWrappedRequest() throws Exception { + wrapped.getAttributes().put("key", "value"); + assertSame(wrapped.getAttributes(), wrapper.getAttributes()); + + ChallengeResponse challengeResponse = new ChallengeResponse(ChallengeScheme.HTTP_BASIC); + wrapper.setChallengeResponse(challengeResponse); + assertSame(challengeResponse, wrapper.getChallengeResponse()); + assertSame(wrapped.getChallengeResponse(), wrapper.getChallengeResponse()); + + assertSame(wrapped.getClientInfo(), wrapper.getClientInfo()); + assertSame(wrapped.getConditions(), wrapper.getConditions()); + + wrapper.setCookies(wrapper.getCookies()); + wrapper.getCookies().add(new Cookie("foo", "bar")); + assertSame(wrapped.getCookies(), wrapper.getCookies()); + + wrapper.setEntity(new StringRepresentation("text")); + assertEquals("text", wrapper.getEntity().getText()); + + wrapper.setEntity("value", MediaType.TEXT_PLAIN); + assertEquals("value", wrapped.getEntity().getText()); + + wrapper.setHostRef("http://localhost"); + assertEquals("http://localhost", wrapper.getHostRef().toString()); + wrapper.setHostRef(new Reference("http://example.com")); + assertEquals("http://example.com", wrapped.getHostRef().toString()); + + wrapper.setMaxForwards(3); + assertEquals(3, wrapper.getMaxForwards()); + + wrapper.setMethod(Method.PUT); + assertEquals(Method.PUT, wrapper.getMethod()); + + wrapper.setOnResponse(null); + assertEquals(wrapped.getOnResponse(), wrapper.getOnResponse()); + + wrapper.setOriginalRef(new Reference("http://original")); + assertEquals("http://original", wrapper.getOriginalRef().toString()); + + wrapper.setProtocol(Protocol.HTTP); + assertEquals(Protocol.HTTP, wrapper.getProtocol()); + + ChallengeResponse proxyChallenge = new ChallengeResponse(ChallengeScheme.HTTP_BASIC); + wrapper.setProxyChallengeResponse(proxyChallenge); + assertSame(proxyChallenge, wrapper.getProxyChallengeResponse()); + + wrapper.setRanges(List.of(new Range(0, 10))); + assertEquals(1, wrapper.getRanges().size()); + + wrapper.setReferrerRef("http://referrer"); + assertEquals("http://referrer", wrapper.getReferrerRef().toString()); + wrapper.setReferrerRef(new Reference("http://referrer2")); + assertEquals("http://referrer2", wrapper.getReferrerRef().toString()); + + wrapper.setResourceRef("http://resource"); + assertEquals("http://resource", wrapper.getResourceRef().toString()); + wrapper.setResourceRef(new Reference("http://resource2")); + assertEquals("http://resource2", wrapper.getResourceRef().toString()); + + wrapper.setRootRef(new Reference("http://root")); + assertEquals("http://root", wrapper.getRootRef().toString()); + + wrapper.setAccessControlRequestHeaders(Set.of("X-Test")); + assertEquals(Set.of("X-Test"), wrapper.getAccessControlRequestHeaders()); + + wrapper.setAccessControlRequestMethod(Method.DELETE); + assertEquals(Method.DELETE, wrapper.getAccessControlRequestMethod()); + + assertFalse(wrapper.isAsynchronous()); + assertFalse(wrapper.isConfidential()); + assertTrue(wrapper.isEntityAvailable()); + assertTrue(wrapper.isExpectingResponse()); + assertTrue(wrapper.isSynchronous()); + + assertEquals(wrapped.toString(), wrapper.toString()); + } + + @Test + void setClientInfoConditionsCookies_delegateToWrappedRequest() { + var clientInfo = new org.restlet.data.ClientInfo(); + wrapper.setClientInfo(clientInfo); + assertSame(clientInfo, wrapped.getClientInfo()); + + var conditions = new org.restlet.data.Conditions(); + wrapper.setConditions(conditions); + assertSame(conditions, wrapped.getConditions()); + } +} diff --git a/org.restlet/src/test/java/org/restlet/util/WrapperResponseTestCase.java b/org.restlet/src/test/java/org/restlet/util/WrapperResponseTestCase.java new file mode 100644 index 0000000000..0ec3d80d7c --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/util/WrapperResponseTestCase.java @@ -0,0 +1,153 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Date; +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.restlet.Request; +import org.restlet.Response; +import org.restlet.data.AuthenticationInfo; +import org.restlet.data.ChallengeRequest; +import org.restlet.data.ChallengeScheme; +import org.restlet.data.Dimension; +import org.restlet.data.MediaType; +import org.restlet.data.Method; +import org.restlet.data.Reference; +import org.restlet.data.ServerInfo; +import org.restlet.data.Status; +import org.restlet.representation.StringRepresentation; + +/** Unit tests for {@link WrapperResponse}. */ +class WrapperResponseTestCase { + + private Request request; + + private Response wrapped; + + private WrapperResponse wrapper; + + @BeforeEach + void setUp() { + request = new Request(); + wrapped = new Response(request); + wrapper = new WrapperResponse(wrapped); + } + + @Test + void abortAndCommit_delegateToWrappedResponse() { + wrapper.abort(); + wrapper.commit(); + } + + @Test + void gettersAndSetters_delegateToWrappedResponse() throws Exception { + wrapper.setAge(42); + assertEquals(42, wrapper.getAge()); + + wrapper.setAllowedMethods(Set.of(Method.GET)); + assertEquals(Set.of(Method.GET), wrapper.getAllowedMethods()); + + wrapped.getAttributes().put("key", "value"); + assertSame(wrapped.getAttributes(), wrapper.getAttributes()); + + AuthenticationInfo authInfo = + new AuthenticationInfo("nextNonce", 1, "cnonce", "auth", "digest"); + wrapper.setAuthenticationInfo(authInfo); + assertSame(authInfo, wrapper.getAuthenticationInfo()); + + wrapper.setAutoCommitting(false); + assertFalse(wrapper.isAutoCommitting()); + + ChallengeRequest challengeRequest = new ChallengeRequest(ChallengeScheme.HTTP_BASIC); + wrapper.setChallengeRequests(List.of(challengeRequest)); + assertEquals(1, wrapper.getChallengeRequests().size()); + + wrapper.getCookieSettings().add(new org.restlet.data.CookieSetting("foo", "bar")); + assertSame(wrapped.getCookieSettings(), wrapper.getCookieSettings()); + + wrapper.setCommitted(true); + assertTrue(wrapper.isCommitted()); + + wrapper.setDimensions(Set.of(Dimension.MEDIA_TYPE)); + assertEquals(Set.of(Dimension.MEDIA_TYPE), wrapper.getDimensions()); + + wrapper.setEntity(new StringRepresentation("text")); + assertEquals("text", wrapper.getEntity().getText()); + wrapper.setEntity("value", MediaType.TEXT_PLAIN); + assertEquals("value", wrapped.getEntity().getText()); + + wrapper.setLocationRef("http://localhost/loc"); + assertEquals("http://localhost/loc", wrapper.getLocationRef().toString()); + wrapper.setLocationRef(new Reference("http://localhost/loc2")); + assertEquals("http://localhost/loc2", wrapper.getLocationRef().toString()); + + wrapper.setProxyChallengeRequests(List.of(challengeRequest)); + assertEquals(1, wrapper.getProxyChallengeRequests().size()); + + assertSame(request, wrapper.getRequest()); + wrapper.setRequest(request); + assertSame(request, wrapped.getRequest()); + wrapper.setRequest(new WrapperRequest(request)); + assertTrue(wrapped.getRequest() instanceof WrapperRequest); + + Date retryAfter = new Date(); + wrapper.setRetryAfter(retryAfter); + assertEquals(retryAfter, wrapper.getRetryAfter()); + + ServerInfo serverInfo = new ServerInfo(); + wrapper.setServerInfo(serverInfo); + assertSame(serverInfo, wrapper.getServerInfo()); + + wrapper.setStatus(Status.SUCCESS_ACCEPTED); + assertEquals(Status.SUCCESS_ACCEPTED, wrapper.getStatus()); + + wrapper.setStatus(Status.SUCCESS_OK, "custom message"); + assertEquals(Status.SUCCESS_OK, wrapper.getStatus()); + + wrapper.setStatus(Status.SERVER_ERROR_INTERNAL, new RuntimeException("boom")); + assertEquals(Status.SERVER_ERROR_INTERNAL, wrapper.getStatus()); + + wrapper.setStatus(Status.SERVER_ERROR_INTERNAL, new RuntimeException("boom"), "message"); + assertEquals(Status.SERVER_ERROR_INTERNAL, wrapper.getStatus()); + + assertFalse(wrapper.isConfidential()); + assertTrue(wrapper.isEntityAvailable()); + + assertEquals(wrapped.toString(), wrapper.toString()); + } + + @Test + void redirectMethods_delegateToWrappedResponse() { + wrapper.redirectPermanent("http://localhost/permanent"); + assertEquals(Status.REDIRECTION_PERMANENT, wrapped.getStatus()); + + wrapper.redirectPermanent(new Reference("http://localhost/permanent2")); + assertEquals(Status.REDIRECTION_PERMANENT, wrapped.getStatus()); + + wrapper.redirectSeeOther("http://localhost/other"); + assertEquals(Status.REDIRECTION_SEE_OTHER, wrapped.getStatus()); + + wrapper.redirectSeeOther(new Reference("http://localhost/other2")); + assertEquals(Status.REDIRECTION_SEE_OTHER, wrapped.getStatus()); + + wrapper.redirectTemporary("http://localhost/temp"); + assertEquals(Status.REDIRECTION_TEMPORARY, wrapped.getStatus()); + + wrapper.redirectTemporary(new Reference("http://localhost/temp2")); + assertEquals(Status.REDIRECTION_TEMPORARY, wrapped.getStatus()); + } +} diff --git a/org.restlet/src/test/java/org/restlet/util/WrapperRestletTestCase.java b/org.restlet/src/test/java/org/restlet/util/WrapperRestletTestCase.java new file mode 100644 index 0000000000..8f28e11465 --- /dev/null +++ b/org.restlet/src/test/java/org/restlet/util/WrapperRestletTestCase.java @@ -0,0 +1,64 @@ +/** + * Copyright 2005-2026 Qlik + *

+ * The content of this file is subject to the terms of the Apache 2.0 open + * source license available at https://www.opensource.org/licenses/apache-2.0 + *

+ * Restlet is a registered trademark of QlikTech International AB. + */ +package org.restlet.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.restlet.Context; +import org.restlet.Request; +import org.restlet.Response; +import org.restlet.Restlet; + +/** Unit tests for {@link WrapperRestlet}. */ +class WrapperRestletTestCase { + + @Test + void delegatesAllOperationsToWrappedRestlet() throws Exception { + Restlet wrapped = new Restlet() {}; + WrapperRestlet wrapper = new WrapperRestlet(wrapped); + + Context context = new Context(); + wrapper.setContext(context); + assertSame(context, wrapper.getContext()); + assertSame(wrapped.getContext(), wrapper.getContext()); + + wrapper.setAuthor("author"); + assertEquals("author", wrapper.getAuthor()); + + wrapper.setDescription("description"); + assertEquals("description", wrapper.getDescription()); + + wrapper.setName("name"); + assertEquals("name", wrapper.getName()); + + wrapper.setOwner("owner"); + assertEquals("owner", wrapper.getOwner()); + + assertSame(wrapped.getLogger(), wrapper.getLogger()); + assertSame(wrapped.getApplication(), wrapper.getApplication()); + + assertFalse(wrapper.isStarted()); + assertTrue(wrapper.isStopped()); + + wrapper.start(); + assertTrue(wrapper.isStarted()); + assertFalse(wrapper.isStopped()); + + wrapper.stop(); + assertTrue(wrapper.isStopped()); + + Request request = new Request(); + Response response = new Response(request); + wrapper.handle(request, response); + } +} diff --git a/pom.xml b/pom.xml index 61a5d6d781..07cf8b84be 100644 --- a/pom.xml +++ b/pom.xml @@ -280,7 +280,7 @@ org.jacoco jacoco-maven-plugin - 0.8.12 + 0.8.15 @@ -307,7 +307,7 @@ INSTRUCTION COVEREDRATIO - 0.50 + 0.70 From 5d07877d3959535bd6dfb1850627c3513692471f Mon Sep 17 00:00:00 2001 From: Thierry Boileau Date: Sat, 4 Jul 2026 20:35:00 +0200 Subject: [PATCH 2/2] Issue #1516: fix Sonar feedbacks --- .../xml/internal/AbstractXmlReaderTestCase.java | 8 ++++++-- .../application/EncodeRepresentationTestCase.java | 5 +++-- .../engine/log/LoggingThreadFactoryTestCase.java | 10 +++++++--- .../engine/log/SimplerFormatterTestCase.java | 14 +++++++------- .../security/CertificateAuthenticatorTestCase.java | 8 ++++++-- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/internal/AbstractXmlReaderTestCase.java b/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/internal/AbstractXmlReaderTestCase.java index 49086790c4..33a2277c19 100644 --- a/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/internal/AbstractXmlReaderTestCase.java +++ b/org.restlet.ext.xml/src/test/java/org/restlet/ext/xml/internal/AbstractXmlReaderTestCase.java @@ -26,10 +26,14 @@ class AbstractXmlReaderTestCase { private static class TestXmlReader extends AbstractXmlReader { @Override - public void parse(InputSource input) {} + public void parse(InputSource input) { + throw new UnsupportedOperationException(); + } @Override - public void parse(String systemId) {} + public void parse(String systemId) { + throw new UnsupportedOperationException(); + } } @Test diff --git a/org.restlet/src/test/java/org/restlet/engine/application/EncodeRepresentationTestCase.java b/org.restlet/src/test/java/org/restlet/engine/application/EncodeRepresentationTestCase.java index 57c79e60e8..73c09b28d5 100644 --- a/org.restlet/src/test/java/org/restlet/engine/application/EncodeRepresentationTestCase.java +++ b/org.restlet/src/test/java/org/restlet/engine/application/EncodeRepresentationTestCase.java @@ -10,6 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayOutputStream; @@ -166,7 +167,7 @@ void write_unsupportedEncoding_delegatesToWrapped() throws Exception { void getReader_whenCanEncode_returnsDecompressibleReader() throws Exception { EncodeRepresentation representation = new EncodeRepresentation(Encoding.GZIP, new StringRepresentation("hello")); - assertTrue(representation.getReader() != null); + assertNotNull(representation.getReader()); } @Test @@ -196,7 +197,7 @@ void write_writerWithEncoding_producesEncodedContent() throws Exception { new EncodeRepresentation(Encoding.GZIP, new StringRepresentation("hello")); StringWriter writer = new StringWriter(); representation.write(writer); - assertTrue(writer.toString().length() > 0); + assertFalse(writer.toString().isEmpty()); } @Test diff --git a/org.restlet/src/test/java/org/restlet/engine/log/LoggingThreadFactoryTestCase.java b/org.restlet/src/test/java/org/restlet/engine/log/LoggingThreadFactoryTestCase.java index 9819cce938..d85e8d4563 100644 --- a/org.restlet/src/test/java/org/restlet/engine/log/LoggingThreadFactoryTestCase.java +++ b/org.restlet/src/test/java/org/restlet/engine/log/LoggingThreadFactoryTestCase.java @@ -43,15 +43,19 @@ void uncaughtExceptionHandler_logsException() throws Exception { Handler captor = new Handler() { @Override - public void publish(LogRecord record) { + public void publish(LogRecord rec) { latch.countDown(); } @Override - public void flush() {} + public void flush() { + throw new UnsupportedOperationException(); + } @Override - public void close() {} + public void close() { + throw new UnsupportedOperationException(); + } }; logger.addHandler(captor); diff --git a/org.restlet/src/test/java/org/restlet/engine/log/SimplerFormatterTestCase.java b/org.restlet/src/test/java/org/restlet/engine/log/SimplerFormatterTestCase.java index d5c159fa11..1b91b6c169 100644 --- a/org.restlet/src/test/java/org/restlet/engine/log/SimplerFormatterTestCase.java +++ b/org.restlet/src/test/java/org/restlet/engine/log/SimplerFormatterTestCase.java @@ -19,10 +19,10 @@ class SimplerFormatterTestCase { @Test void format_withoutThrowable_includesLevelLoggerAndMessage() { - LogRecord record = new LogRecord(Level.INFO, "hello"); - record.setLoggerName("my.logger"); + LogRecord rec = new LogRecord(Level.INFO, "hello"); + rec.setLoggerName("my.logger"); - String result = new SimplerFormatter().format(record); + String result = new SimplerFormatter().format(rec); assertTrue(result.contains(Level.INFO.getLocalizedName())); assertTrue(result.contains("my.logger")); @@ -31,11 +31,11 @@ void format_withoutThrowable_includesLevelLoggerAndMessage() { @Test void format_withThrowable_appendsStackTrace() { - LogRecord record = new LogRecord(Level.SEVERE, "boom"); - record.setLoggerName("my.logger"); - record.setThrown(new RuntimeException("failure")); + LogRecord rec = new LogRecord(Level.SEVERE, "boom"); + rec.setLoggerName("my.logger"); + rec.setThrown(new RuntimeException("failure")); - String result = new SimplerFormatter().format(record); + String result = new SimplerFormatter().format(rec); assertTrue(result.contains("boom")); assertTrue(result.contains("RuntimeException")); diff --git a/org.restlet/src/test/java/org/restlet/security/CertificateAuthenticatorTestCase.java b/org.restlet/src/test/java/org/restlet/security/CertificateAuthenticatorTestCase.java index 9d067ce89a..fc76b46cf8 100644 --- a/org.restlet/src/test/java/org/restlet/security/CertificateAuthenticatorTestCase.java +++ b/org.restlet/src/test/java/org/restlet/security/CertificateAuthenticatorTestCase.java @@ -99,10 +99,14 @@ public byte[] getEncoded() { } @Override - public void verify(java.security.PublicKey key) {} + public void verify(java.security.PublicKey key) { + throw new UnsupportedOperationException(); + } @Override - public void verify(java.security.PublicKey key, String sigProvider) {} + public void verify(java.security.PublicKey key, String sigProvider) { + throw new UnsupportedOperationException(); + } @Override public String toString() {