package org.jboss.resteasy.test.providers.multipart;

import java.lang.reflect.ReflectPermission;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Random;

import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.core.Response;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit5.ArquillianExtension;
import org.jboss.resteasy.test.providers.multipart.resource.InputPartDefaultCharsetOverwriteContentTypeCharsetUTF16;
import org.jboss.resteasy.test.providers.multipart.resource.InputPartDefaultCharsetOverwriteContentTypeCharsetUTF8;
import org.jboss.resteasy.test.providers.multipart.resource.InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF16;
import org.jboss.resteasy.test.providers.multipart.resource.InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF8;
import org.jboss.resteasy.test.providers.multipart.resource.InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF16;
import org.jboss.resteasy.test.providers.multipart.resource.InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF8;
import org.jboss.resteasy.test.providers.multipart.resource.InputPartDefaultCharsetOverwriteService;
import org.jboss.resteasy.util.Encode;
import org.jboss.resteasy.utils.PortProviderUtil;
import org.jboss.resteasy.utils.TestUtil;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.wildfly.testing.tools.deployments.DeploymentDescriptors;

/**
 * @tpSubChapter Multipart provider
 * @tpChapter Integration tests
 * @tpTestCaseDetails Regression test for RESTEASY-723
 * @tpSince RESTEasy 3.0.16
 */
@ExtendWith(ArquillianExtension.class)
@RunAsClient
public class InputPartDefaultCharsetOverwriteTest {
    private static final org.jboss.logging.Logger logger = org.jboss.logging.Logger
            .getLogger(InputPartDefaultCharsetOverwriteTest.class);

    static Client client;

    public static final String UTF_8 = "UTF-8";
    public static final String UTF_16 = "UTF-16";
    public static final String TEXT_PLAIN = "text/plain";
    public static final String TEXT_HTTP = "text/http";
    public static final String TEXT_PLAIN_WITH_CHARSET_US_ASCII = normalize("text/plain; charset=US-ASCII");
    public static final String TEXT_PLAIN_WITH_CHARSET_UTF_16 = normalize("text/plain; charset=UTF-16");
    public static final String TEXT_HTTP_WITH_CHARSET_US_ASCII = normalize("text/http; charset=US-ASCII");
    public static final String TEXT_HTTP_WITH_CHARSET_UTF_8 = normalize("text/http; charset=UTF-8");
    public static final String TEXT_HTTP_WITH_CHARSET_UTF_16 = normalize("text/http; charset=UTF-16");
    public static final String APPLICATION_XML = normalize("application/xml");
    public static final String APPLICATION_XML_WITH_CHARSET_US_ASCII = normalize("application/xml; charset=US-ASCII");
    public static final String APPLICATION_XML_WITH_CHARSET_UTF_8 = normalize("application/xml; charset=UTF-8");
    public static final String APPLICATION_XML_WITH_CHARSET_UTF_16 = normalize("application/xml; charset=UTF-16");
    public static final String APPLICATION_OCTET_STREAM = normalize("application/octet-stream");
    public static final String abc_us_ascii = "abc";
    public static final byte[] abc_us_ascii_bytes = abc_us_ascii.getBytes(Charset.forName("us-ascii"));
    public static final String abc_utf8 = new String("abc\u20AC");
    public static final byte[] abc_utf8_bytes = abc_utf8.getBytes(StandardCharsets.UTF_8);
    public static final String abc_utf16 = new String("abc\u20AC");
    public static final byte[] abc_utf16_bytes = abc_utf16.getBytes(Charset.forName("utf-16"));
    public static final String TEXT_PLAIN_WITH_CHARSET_UTF_8 = normalize("text/plain; charset=UTF-8");

    @BeforeAll
    public static void init() {
        client = ClientBuilder.newClient();
    }

    @AfterAll
    public static void after() throws Exception {
        client.close();
        client = null;
    }

    @Deployment(name = "InputPartDefaultCharsetOverwriteTest")
    public static Archive<?> createTestArchiveBasic() {
        WebArchive war = TestUtil.prepareArchive(InputPartDefaultCharsetOverwriteTest.class.getSimpleName());
        war.addClasses(InputPartDefaultCharsetOverwriteTest.class);
        war.addClasses(TestUtil.class, PortProviderUtil.class);
        war.addAsManifestResource(DeploymentDescriptors.createPermissionsXmlAsset(
                new ReflectPermission("suppressAccessChecks")), "permissions.xml");
        return TestUtil.finishContainerPrepare(war, null, InputPartDefaultCharsetOverwriteService.class);
    }

    @Deployment(name = "InputPartDefaultCharsetOverwriteContentTypeCharsetUTF8")
    public static Archive<?> createTestArchiveContentTypeCharsetUTF8() {
        WebArchive war = TestUtil.prepareArchive(InputPartDefaultCharsetOverwriteContentTypeCharsetUTF8.class.getSimpleName());
        war.addClasses(InputPartDefaultCharsetOverwriteTest.class);
        war.addClasses(TestUtil.class, PortProviderUtil.class);
        return TestUtil.finishContainerPrepare(war, null, InputPartDefaultCharsetOverwriteContentTypeCharsetUTF8.class,
                InputPartDefaultCharsetOverwriteService.class);
    }

    @Deployment(name = "InputPartDefaultCharsetOverwriteContentTypeCharsetUTF16")
    public static Archive<?> createTestArchiveContentTypeCharsetUTF8ContentTypeCharsetUTF16() {
        WebArchive war = TestUtil.prepareArchive(InputPartDefaultCharsetOverwriteContentTypeCharsetUTF16.class.getSimpleName());
        war.addClasses(InputPartDefaultCharsetOverwriteTest.class);
        war.addClasses(TestUtil.class, PortProviderUtil.class);
        return TestUtil.finishContainerPrepare(war, null, InputPartDefaultCharsetOverwriteContentTypeCharsetUTF16.class,
                InputPartDefaultCharsetOverwriteService.class);
    }

    @Deployment(name = "InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF8")
    public static Archive<?> createTestArchiveContentTypeNoCharsetUTF8() {
        WebArchive war = TestUtil
                .prepareArchive(InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF8.class.getSimpleName());
        war.addClasses(InputPartDefaultCharsetOverwriteTest.class);
        war.addClasses(TestUtil.class, PortProviderUtil.class);
        return TestUtil.finishContainerPrepare(war, null, InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF8.class,
                InputPartDefaultCharsetOverwriteService.class);
    }

    @Deployment(name = "InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF16")
    public static Archive<?> createTestArchiveContentTypeNoCharsetUTF16() {
        WebArchive war = TestUtil
                .prepareArchive(InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF16.class.getSimpleName());
        war.addClasses(InputPartDefaultCharsetOverwriteTest.class);
        war.addClasses(TestUtil.class, PortProviderUtil.class);
        return TestUtil.finishContainerPrepare(war, null, InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF16.class,
                InputPartDefaultCharsetOverwriteService.class);
    }

    @Deployment(name = "InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF8")
    public static Archive<?> createTestArchiveNoContentTypeCharsetUTF8() {
        WebArchive war = TestUtil
                .prepareArchive(InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF8.class.getSimpleName());
        war.addClasses(InputPartDefaultCharsetOverwriteTest.class);
        war.addClasses(TestUtil.class, PortProviderUtil.class);
        return TestUtil.finishContainerPrepare(war, null, InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF8.class,
                InputPartDefaultCharsetOverwriteService.class);
    }

    @Deployment(name = "InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF16")
    public static Archive<?> createTestArchiveNoContentTypeCharsetUTF16() {
        WebArchive war = TestUtil
                .prepareArchive(InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF16.class.getSimpleName());
        war.addClasses(InputPartDefaultCharsetOverwriteTest.class);
        war.addClasses(TestUtil.class, PortProviderUtil.class);
        return TestUtil.finishContainerPrepare(war, null, InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF16.class,
                InputPartDefaultCharsetOverwriteService.class);
    }

    /**
     * @tpTestDetails Test UTF8 content-type, no charset, preprocessor with no content-type
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testUTF8ContentTypeNoCharsetPreprocessorWithNoContentTypeCharset() throws Exception {
        doTestWithContentTypeInMessage(abc_utf8_bytes, abc_utf8, TEXT_PLAIN, TEXT_PLAIN_WITH_CHARSET_UTF_8,
                InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF8.class);
    }

    /**
     * @tpTestDetails The tests use no interceptor.
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void noInterceptorTest() throws Exception {
        // testNoContentTypeDefault
        doTestNoContentTypeInMessage(abc_us_ascii_bytes, abc_us_ascii, TEXT_PLAIN_WITH_CHARSET_US_ASCII,
                InputPartDefaultCharsetOverwriteTest.class);
        // testContentTypeNoCharsetDefault
        doTestWithContentTypeInMessage(abc_us_ascii_bytes, abc_us_ascii, TEXT_HTTP,
                TEXT_HTTP_WITH_CHARSET_US_ASCII, InputPartDefaultCharsetOverwriteTest.class);
        // testContentTypeCharsetDefaultUTF8
        doTestWithContentTypeInMessage(abc_utf8_bytes, abc_utf8, TEXT_HTTP_WITH_CHARSET_UTF_8,
                TEXT_HTTP_WITH_CHARSET_UTF_8, InputPartDefaultCharsetOverwriteTest.class);
        // testContentTypeCharsetDefaultUTF16
        doTestWithContentTypeInMessage(abc_utf16_bytes, abc_utf16, TEXT_HTTP_WITH_CHARSET_UTF_16,
                TEXT_HTTP_WITH_CHARSET_UTF_16, InputPartDefaultCharsetOverwriteTest.class);
        // testNoContentTypeInputPartContentTypeUTF8
        doTestNoContentTypeInMessageContentTypeInQuery(abc_utf8_bytes, abc_utf8, TEXT_HTTP_WITH_CHARSET_UTF_8,
                TEXT_HTTP_WITH_CHARSET_UTF_8, InputPartDefaultCharsetOverwriteTest.class);
        // testNoContentTypeInputPartContentTypeUTF16
        doTestNoContentTypeInMessageContentTypeInQuery(abc_utf16_bytes, abc_utf16, TEXT_HTTP_WITH_CHARSET_UTF_16,
                TEXT_HTTP_WITH_CHARSET_UTF_16, InputPartDefaultCharsetOverwriteTest.class);
        // testContentTypeInputPartContentTypeUTF8
        doTestWithContentTypeInMessageContentTypeInQuery(abc_utf8_bytes, abc_utf8, TEXT_HTTP_WITH_CHARSET_UTF_16,
                TEXT_HTTP_WITH_CHARSET_UTF_8,
                TEXT_HTTP_WITH_CHARSET_UTF_8, InputPartDefaultCharsetOverwriteTest.class);
        // testContentTypeInputPartContentTypeUTF16
        doTestWithContentTypeInMessageContentTypeInQuery(abc_utf16_bytes, abc_utf16, TEXT_HTTP_WITH_CHARSET_UTF_8,
                TEXT_HTTP_WITH_CHARSET_UTF_16,
                TEXT_HTTP_WITH_CHARSET_UTF_16, InputPartDefaultCharsetOverwriteTest.class);
    }

    /**
     * @tpTestDetails The tests use an interceptor that installs a content-type but no charset.
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void interceptorNoCharsetYesContentType() throws Exception {
        // testNoContentTypePreprocessorWithContentTypeNoCharsetUTF8
        doTestNoContentTypeInMessage(abc_utf8_bytes, abc_utf8, TEXT_HTTP_WITH_CHARSET_UTF_8,
                InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF8.class);
        // testNoContentTypePreprocessorWithContentTypeNoCharsetUTF16
        doTestNoContentTypeInMessage(abc_utf16_bytes, abc_utf16, TEXT_HTTP_WITH_CHARSET_UTF_16,
                InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF16.class);
        // testContentTypeNoCharsetPreprocessorWithContentTypeNoCharsetUTF8
        doTestWithContentTypeInMessage(abc_utf8_bytes, abc_utf8, TEXT_PLAIN, TEXT_PLAIN_WITH_CHARSET_UTF_8,
                InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF8.class);
        // testContentTypeNoCharsetPreprocessorWithContentTypeNoCharsetUTF16
        doTestWithContentTypeInMessage(abc_utf16_bytes, abc_utf16, TEXT_PLAIN, TEXT_PLAIN_WITH_CHARSET_UTF_16,
                InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF16.class);
        // testContentTypeCharsetPreprocessorWithContentTypeNoCharsetUTF8
        doTestWithContentTypeInMessage(abc_utf8_bytes, abc_utf8, TEXT_PLAIN_WITH_CHARSET_UTF_8, TEXT_PLAIN_WITH_CHARSET_UTF_8,
                InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF16.class);
        // testContentTypeCharsetPreprocessorWithContentTypeNoCharsetUTF16
        doTestWithContentTypeInMessage(abc_utf16_bytes, abc_utf16, TEXT_PLAIN_WITH_CHARSET_UTF_16,
                TEXT_PLAIN_WITH_CHARSET_UTF_16,
                InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF8.class);
        // testNoContentTypePreprocessorWithContentTypeNoCharsetInputPartContentTypeUTF8
        doTestNoContentTypeInMessageContentTypeInQuery(abc_utf8_bytes, abc_utf8, TEXT_HTTP_WITH_CHARSET_UTF_8,
                TEXT_HTTP_WITH_CHARSET_UTF_8,
                InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF16.class);
        // testNoContentTypePreprocessorWithContentTypeNoCharsetInputPartContentTypeUTF16
        doTestNoContentTypeInMessageContentTypeInQuery(abc_utf16_bytes, abc_utf16, TEXT_HTTP_WITH_CHARSET_UTF_16,
                TEXT_HTTP_WITH_CHARSET_UTF_16,
                InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF8.class);
        // testContentTypePreprocessorWithContentTypeNoCharsetInputPartContentTypeUTF8
        doTestWithContentTypeInMessageContentTypeInQuery(abc_utf8_bytes, abc_utf8, TEXT_HTTP_WITH_CHARSET_UTF_16,
                TEXT_HTTP_WITH_CHARSET_UTF_8,
                TEXT_HTTP_WITH_CHARSET_UTF_8, InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF16.class);
        // testContentTypereprocessorWithContentTypeNoCharsetInputPartContentTypeUTF16
        doTestWithContentTypeInMessageContentTypeInQuery(abc_utf16_bytes, abc_utf16, TEXT_HTTP_WITH_CHARSET_UTF_8,
                TEXT_HTTP_WITH_CHARSET_UTF_16,
                TEXT_HTTP_WITH_CHARSET_UTF_16, InputPartDefaultCharsetOverwriteContentTypeNoCharsetUTF8.class);
    }

    /**
     * @tpTestDetails The tests use an interceptor that installs a charset but no content-type.
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testNoContentTypePreprocessorWithNoContentTypeCharsetUTF8() throws Exception {
        // testNoContentTypePreprocessorWithNoContentTypeCharsetUTF8
        doTestNoContentTypeInMessage(abc_utf8_bytes, abc_utf8, TEXT_PLAIN_WITH_CHARSET_UTF_8,
                InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF8.class);
        // testNoContentTypePreprocessorWithNoContentTypeCharsetUTF16
        doTestNoContentTypeInMessage(abc_utf16_bytes, abc_utf16, TEXT_PLAIN_WITH_CHARSET_UTF_16,
                InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF16.class);
        // testContentTypeNoCharsetPreprocessorWithNoContentTypeCharsetUTF8
        doTestWithContentTypeInMessage(abc_utf8_bytes, abc_utf8, TEXT_HTTP, TEXT_HTTP_WITH_CHARSET_UTF_8,
                InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF8.class);
        // testContentTypeNoCharsetPreprocessorWithNoContentTypeCharsetUTF16
        doTestWithContentTypeInMessage(abc_utf16_bytes, abc_utf16, TEXT_HTTP, TEXT_HTTP_WITH_CHARSET_UTF_16,
                InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF16.class);
        // testContentTypeCharsetPreprocessorWithNoContentTypeCharset8
        doTestWithContentTypeInMessage(abc_utf8_bytes, abc_utf8, TEXT_PLAIN_WITH_CHARSET_UTF_8, TEXT_PLAIN_WITH_CHARSET_UTF_8,
                InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF16.class);
        // testContentTypeCharsetPreprocessorWithNoContentTypeCharset16
        doTestWithContentTypeInMessage(abc_utf16_bytes, abc_utf16, TEXT_PLAIN_WITH_CHARSET_UTF_16,
                TEXT_PLAIN_WITH_CHARSET_UTF_16,
                InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF8.class);
        // testNoContentTypePreprocessorWithNoContentTypeCharsetInputPartContentTypeUTF8
        doTestNoContentTypeInMessageContentTypeInQuery(abc_utf8_bytes, abc_utf8, TEXT_HTTP_WITH_CHARSET_UTF_8,
                TEXT_HTTP_WITH_CHARSET_UTF_8,
                InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF16.class);
        // testNoContentTypePreprocessorWithNoContentTypeCharsetInputPartContentTypeUTF16
        doTestNoContentTypeInMessageContentTypeInQuery(abc_utf16_bytes, abc_utf16, TEXT_HTTP_WITH_CHARSET_UTF_16,
                TEXT_HTTP_WITH_CHARSET_UTF_16, InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF8.class);
        // testContentTypePreprocessorWithNoContentTypeCharsetInputPartContentTypeUTF8
        doTestWithContentTypeInMessageContentTypeInQuery(abc_utf8_bytes, abc_utf8, TEXT_HTTP_WITH_CHARSET_UTF_16,
                TEXT_HTTP_WITH_CHARSET_UTF_8,
                TEXT_HTTP_WITH_CHARSET_UTF_8, InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF16.class);
        // testContentTypereprocessorWithNoContentTypeCharsetInputPartContentTypeUTF16
        doTestWithContentTypeInMessageContentTypeInQuery(abc_utf16_bytes, abc_utf16, TEXT_HTTP_WITH_CHARSET_UTF_8,
                TEXT_HTTP_WITH_CHARSET_UTF_16,
                TEXT_HTTP_WITH_CHARSET_UTF_16, InputPartDefaultCharsetOverwriteNoContentTypeCharsetUTF8.class);
    }

    /**
     * @tpTestDetails The tests use an interceptor that installs both a content-type and a charset.
     * @tpSince RESTEasy 3.0.16
     */
    @Test
    public void testNoContentTypePreprocessorWithContentTypeCharset8() throws Exception {
        // testNoContentTypePreprocessorWithContentTypeCharset8
        doTestNoContentTypeInMessage(abc_utf8_bytes, abc_utf8, TEXT_HTTP_WITH_CHARSET_UTF_8,
                InputPartDefaultCharsetOverwriteContentTypeCharsetUTF8.class);
        // testNoContentTypePreprocessorWithContentTypeCharset16
        doTestNoContentTypeInMessage(abc_utf16_bytes, abc_utf16, TEXT_HTTP_WITH_CHARSET_UTF_16,
                InputPartDefaultCharsetOverwriteContentTypeCharsetUTF16.class);
        // testContentTypeNoCharsetPreprocessorWithContentTypeCharset8
        doTestWithContentTypeInMessage(abc_utf8_bytes, abc_utf8, TEXT_PLAIN, TEXT_PLAIN_WITH_CHARSET_UTF_8,
                InputPartDefaultCharsetOverwriteContentTypeCharsetUTF8.class);
        // testContentTypeNoCharsetPreprocessorWithContentTypeCharset16
        doTestWithContentTypeInMessage(abc_utf16_bytes, abc_utf16, TEXT_PLAIN, TEXT_PLAIN_WITH_CHARSET_UTF_16,
                InputPartDefaultCharsetOverwriteContentTypeCharsetUTF16.class);
        // testContentTypeCharsetPreprocessorWithContentTypeCharset8
        doTestWithContentTypeInMessage(abc_utf8_bytes, abc_utf8, TEXT_PLAIN_WITH_CHARSET_UTF_8, TEXT_PLAIN_WITH_CHARSET_UTF_8,
                InputPartDefaultCharsetOverwriteContentTypeCharsetUTF16.class);
        // testContentTypeCharsetPreprocessorWithContentTypeCharset16
        doTestWithContentTypeInMessage(abc_utf16_bytes, abc_utf16, TEXT_PLAIN_WITH_CHARSET_UTF_16,
                TEXT_PLAIN_WITH_CHARSET_UTF_16,
                InputPartDefaultCharsetOverwriteContentTypeCharsetUTF8.class);
        // testNoContentTypePreprocessorWithContentTypeCharsetInputPartContentTypeUTF8
        doTestNoContentTypeInMessageContentTypeInQuery(abc_utf8_bytes, abc_utf8, TEXT_HTTP_WITH_CHARSET_UTF_8,
                TEXT_HTTP_WITH_CHARSET_UTF_8,
                InputPartDefaultCharsetOverwriteContentTypeCharsetUTF16.class);
        // testNoContentTypePreprocessorWithContentTypeCharsetInputPartContentTypeUTF16
        doTestNoContentTypeInMessageContentTypeInQuery(abc_utf16_bytes, abc_utf16, TEXT_HTTP_WITH_CHARSET_UTF_16,
                TEXT_HTTP_WITH_CHARSET_UTF_16,
                InputPartDefaultCharsetOverwriteContentTypeCharsetUTF8.class);
        // testContentTypePreprocessorWithContentTypeCharsetInputPartContentTypeUTF8
        doTestWithContentTypeInMessageContentTypeInQuery(abc_utf8_bytes, abc_utf8, TEXT_HTTP_WITH_CHARSET_UTF_16,
                TEXT_HTTP_WITH_CHARSET_UTF_8,
                TEXT_HTTP_WITH_CHARSET_UTF_8, InputPartDefaultCharsetOverwriteContentTypeCharsetUTF16.class);
        // testContentTypereprocessorWithContentTypeCharsetInputPartContentTypeUTF16
        doTestWithContentTypeInMessageContentTypeInQuery(abc_utf16_bytes, abc_utf16, TEXT_HTTP_WITH_CHARSET_UTF_8,
                TEXT_HTTP_WITH_CHARSET_UTF_16,
                TEXT_HTTP_WITH_CHARSET_UTF_16, InputPartDefaultCharsetOverwriteContentTypeCharsetUTF8.class);
    }

    /**
     * @tpTestDetails The tests use a non-text media type.
     * @tpSince RESTEasy 3.0.16
     */
    //////////////////////////////////////////////////////////////////////////////////////////
    //
    //////////////////////////////////////////////////////////////////////////////////////////
    @Test
    public void testApplicationXmlUSAscii() throws Exception {
        // testApplicationXmlUSAscii
        doTestWithContentTypeInMessage(abc_us_ascii_bytes, abc_us_ascii, APPLICATION_XML_WITH_CHARSET_US_ASCII,
                APPLICATION_XML_WITH_CHARSET_US_ASCII, InputPartDefaultCharsetOverwriteTest.class);
        // testApplicationXmlUTF8
        doTestWithContentTypeInMessage(abc_utf8_bytes, abc_utf8, APPLICATION_XML_WITH_CHARSET_UTF_8,
                APPLICATION_XML_WITH_CHARSET_UTF_8, InputPartDefaultCharsetOverwriteTest.class);
        // testApplicationXmlUTF16
        doTestWithContentTypeInMessage(abc_utf16_bytes, abc_utf16, APPLICATION_XML_WITH_CHARSET_UTF_16,
                APPLICATION_XML_WITH_CHARSET_UTF_16, InputPartDefaultCharsetOverwriteTest.class);
        // testApplicationOctetStreamUSAscii
        doTestByteArray(abc_us_ascii_bytes, APPLICATION_OCTET_STREAM, InputPartDefaultCharsetOverwriteTest.class);
        // testApplicationOctetStreamUTF8
        doTestByteArray(abc_utf8_bytes, APPLICATION_OCTET_STREAM, InputPartDefaultCharsetOverwriteTest.class);
        // testApplicationOctetStreamUTF16
        doTestByteArray(abc_utf16_bytes, APPLICATION_OCTET_STREAM, InputPartDefaultCharsetOverwriteTest.class);
        // testByteArray
        byte[] body = new byte[512];
        Random r = new Random(System.currentTimeMillis());
        r.nextBytes(body);
        doTestByteArray(body, APPLICATION_OCTET_STREAM, InputPartDefaultCharsetOverwriteTest.class);
    }

    private static void doTestNoContentTypeInMessage(byte[] body, String expectedBody, String expectedContentType,
            Class<?> providerClass) throws Exception {
        byte[] start = ("--boo\r\nContent-Disposition: form-data; name=\"foo\"\r\nContent-Transfer-Encoding: 8bit\r\n\r\n")
                .getBytes();
        byte[] end = "\r\n--boo--\r\n".getBytes();
        byte[] buf = new byte[start.length + body.length + end.length];
        int pos0 = 0;
        int pos1 = pos0 + start.length;
        int pos2 = pos1 + body.length;
        System.arraycopy(start, 0, buf, pos0, start.length);
        System.arraycopy(body, 0, buf, pos1, body.length);
        System.arraycopy(end, 0, buf, pos2, end.length);
        Response response = client.target(PortProviderUtil.generateURL("/test/", providerClass.getSimpleName())).request()
                .post(Entity.entity(buf, "multipart/form-data; boundary=boo"));
        String responseStr = response.readEntity(String.class);
        logger.info("status: " + response.getStatus());
        logger.info("client response: " + responseStr);
        Assertions.assertEquals(20, response.getStatus() / 10,
                "Status code is wrong.");
        String[] answer = responseStr.split(":");
        Assertions.assertEquals(3, answer.length, "Wrong size of response");
        logger.info("response charset: " + answer[0]);
        Assertions.assertEquals(normalize(expectedContentType), normalize(answer[0]),
                "Response has wrong encoding");
        Assertions.assertEquals(expectedBody, answer[1], "Wrong content of response");
        Assertions.assertEquals(expectedBody, answer[2], "Wrong content of response");
        response.close();
    }

    private static void doTestWithContentTypeInMessage(byte[] body, String expectedBody, String inputContentType,
            String expectedContentType, Class<?> deployment) throws Exception {
        byte[] start = ("--boo\r\nContent-Disposition: form-data; name=\"foo\"\r\nContent-Type: ").getBytes();
        byte[] middle = (inputContentType + "\r\n\r\n").getBytes();
        byte[] end = "\r\n--boo--\r\n".getBytes();
        byte[] buf = new byte[start.length + middle.length + body.length + end.length];
        int pos0 = 0;
        int pos1 = pos0 + start.length;
        int pos2 = pos1 + middle.length;
        int pos3 = pos2 + body.length;
        System.arraycopy(start, 0, buf, pos0, start.length);
        System.arraycopy(middle, 0, buf, pos1, middle.length);
        System.arraycopy(body, 0, buf, pos2, body.length);
        System.arraycopy(end, 0, buf, pos3, end.length);
        Response response = client.target(PortProviderUtil.generateURL("/test/", deployment.getSimpleName())).request()
                .post(Entity.entity(buf, "multipart/form-data; boundary=boo"));
        String responseStr = response.readEntity(String.class);
        logger.info("status: " + response.getStatus());
        logger.info("client response: " + responseStr);
        Assertions.assertEquals(20, response.getStatus() / 10, "Status code is wrong.");
        String[] answer = responseStr.split(":");
        Assertions.assertEquals(3, answer.length, "Wrong size of response");
        logger.info("response charset: " + answer[0]);
        Assertions.assertEquals(normalize(expectedContentType), normalize(answer[0]),
                "Response has wrong encoding");
        Assertions.assertEquals(expectedBody, answer[1], "Wrong content of response");
        Assertions.assertEquals(expectedBody, answer[2], "Wrong content of response");
    }

    private static void doTestNoContentTypeInMessageContentTypeInQuery(
            byte[] body, String expectedBody, String queryContentType, String expectedContentType, Class<?> deployment)
            throws Exception {
        byte[] start = ("--boo\r\nContent-Disposition: form-data; name=\"foo\"\r\nContent-Transfer-Encoding: 8bit\r\n\r\n")
                .getBytes();
        byte[] end = "\r\n--boo--\r\n".getBytes();
        byte[] buf = new byte[start.length + body.length + end.length];
        int pos0 = 0;
        int pos1 = pos0 + start.length;
        int pos2 = pos1 + body.length;
        System.arraycopy(start, 0, buf, pos0, start.length);
        System.arraycopy(body, 0, buf, pos1, body.length);
        System.arraycopy(end, 0, buf, pos2, end.length);
        Response response = client
                .target(PortProviderUtil.generateURL("/query?contentType=" + Encode.encodeQueryParamAsIs(queryContentType),
                        deployment.getSimpleName()))
                .request()
                .post(Entity.entity(buf, "multipart/form-data; boundary=boo"));
        String responseStr = response.readEntity(String.class);
        logger.info("status: " + response.getStatus());
        logger.info("client response: " + responseStr);
        Assertions.assertEquals(20, response.getStatus() / 10, "Status code is wrong.");
        String[] answer = responseStr.split(":");
        Assertions.assertEquals(3, answer.length, "Wrong size of response");
        logger.info("response charset: " + answer[0]);
        Assertions.assertEquals(normalize(expectedContentType), normalize(answer[0]),
                "Response has wrong encoding");
        Assertions.assertEquals(expectedBody, answer[1], "Wrong content of response");
        Assertions.assertEquals(expectedBody, answer[2], "Wrong content of response");
    }

    private static void doTestWithContentTypeInMessageContentTypeInQuery(
            byte[] body, String expectedBody, String inputContentType, String queryContentType, String expectedContentType,
            Class<?> deployment) throws Exception {
        byte[] start = ("--boo\r\nContent-Disposition: form-data; name=\"foo\"\r\nContent-Type: ").getBytes();
        byte[] middle = (inputContentType + "\r\n\r\n").getBytes();
        byte[] end = "\r\n--boo--\r\n".getBytes();
        byte[] buf = new byte[start.length + middle.length + body.length + end.length];
        int pos0 = 0;
        int pos1 = pos0 + start.length;
        int pos2 = pos1 + middle.length;
        int pos3 = pos2 + body.length;
        System.arraycopy(start, 0, buf, pos0, start.length);
        System.arraycopy(middle, 0, buf, pos1, middle.length);
        System.arraycopy(body, 0, buf, pos2, body.length);
        System.arraycopy(end, 0, buf, pos3, end.length);
        Response response = client
                .target(PortProviderUtil.generateURL("/query?contentType=" + Encode.encodeQueryParamAsIs(queryContentType),
                        deployment.getSimpleName()))
                .request()
                .post(Entity.entity(buf, "multipart/form-data; boundary=boo"));
        String responseStr = response.readEntity(String.class);
        logger.info("status: " + response.getStatus());
        logger.info("client response: " + responseStr);
        Assertions.assertEquals(20, response.getStatus() / 10, "Status code is wrong.");
        String[] answer = responseStr.split(":");
        Assertions.assertEquals(3, answer.length, "Wrong size of response");
        logger.info("response charset: " + answer[0]);
        Assertions.assertEquals(normalize(expectedContentType), normalize(answer[0]),
                "Response has wrong encoding");
        Assertions.assertEquals(expectedBody, answer[1], "Wrong content of response");
        Assertions.assertEquals(expectedBody, answer[2], "Wrong content of response");
    }

    private static void doTestByteArray(byte[] body, String contentType, Class<?> deployment) throws Exception {
        byte[] start = ("--boo\r\nContent-Disposition: form-data; name=\"foo\"\r\nContent-Type: " + contentType + "\r\n\r\n")
                .getBytes();
        byte[] end = "\r\n--boo--\r\n".getBytes();
        byte[] buf = new byte[start.length + body.length + end.length];
        int pos0 = 0;
        int pos1 = pos0 + start.length;
        int pos2 = pos1 + body.length;
        System.arraycopy(start, 0, buf, pos0, start.length);
        System.arraycopy(body, 0, buf, pos1, body.length);
        System.arraycopy(end, 0, buf, pos2, end.length);
        Response response = client.target(PortProviderUtil.generateURL("/bytes/", deployment.getSimpleName())).request()
                .post(Entity.entity(buf, "multipart/form-data; boundary=boo"));
        logger.info("status: " + response.getStatus());
        Assertions.assertEquals(20, response.getStatus() / 10, "Status code is wrong.");
        byte[] b = response.readEntity(byte[].class);
        for (int i = 0; i < body.length; i++) {
            StringBuilder errorMessage = new StringBuilder();
            errorMessage.append("Wrong content of response: ").append(i).append(": ").append(body[i]).append(" != ")
                    .append(b[i]);
            Assertions.assertEquals(body[i], b[i], errorMessage.toString());
        }
    }

    private static String normalize(String s) {
        String sl = s.toLowerCase();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length(); i++) {
            if (sl.charAt(i) != ' ' && sl.charAt(i) != '"') {
                sb.append(sl.charAt(i));
            }
        }
        return sb.toString();
    }
}
