<commit_before>package com.maxmind.minfraud;

import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.maxmind.minfraud.exception.*;
import com.maxmind.minfraud.request.Device;
import com.maxmind.minfraud.request.Shipping;
import com.maxmind.minfraud.request.Transaction;
import com.maxmind.minfraud.response.FactorsResponse;
import com.maxmind.minfraud.response.InsightsResponse;
import com.maxmind.minfraud.response.ScoreResponse;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.skyscreamer.jsonassert.JSONAssert;

import java.net.InetAddress;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.jcabi.matchers.RegexMatchers.matchesPattern;
import static com.maxmind.minfraud.request.RequestTestHelper.*;
import static org.hamcrest.core.StringStartsWith.startsWith;
import static org.junit.Assert.*;
import static org.hamcrest.MatcherAssert.assertThat;

@RunWith(JUnitParamsRunner.class)
public class WebServiceClientTest {
    @Rule
    public final WireMockRule wireMockRule = new WireMockRule(0); // 0 picks random port

    @Test
    public void testFullScoreTransaction() throws Exception {
        String responseContent = readJsonFile("score-response");
        try (WebServiceClient client = createSuccessClient("score", responseContent)) {
            Transaction request = fullTransaction();
            ScoreResponse response = client.score(request);

            JSONAssert.assertEquals(responseContent, response.toJson(), true);
            verifyRequestFor("score", "full-request");
        }
    }

    @Test
    public void testFullScoreTransactionWithEmailMd5() throws Exception {
        String responseContent = readJsonFile("score-response");
        try (WebServiceClient client = createSuccessClient("score", responseContent)) {
            Transaction request = fullTransactionEmailMd5();
            ScoreResponse response = client.score(request);

            JSONAssert.assertEquals(responseContent, response.toJson(), true);
            verifyRequestFor("score", "full-request-email-md5");
        }
    }

    @Test
    public void testFullInsightsTransaction() throws Exception {
        String responseContent = readJsonFile("insights-response");
        try (WebServiceClient client = createSuccessClient("insights", responseContent)) {
            Transaction request = fullTransaction();
            InsightsResponse response = client.insights(request);

            // We use non-strict checking as there is some extra stuff in the serialized
            // object, most notably the "name" field in the GeoIP2 InsightsResponse subobjects.
            // We cannot change this as it would be a breaking change to the GeoIP2 API.
            JSONAssert.assertEquals(responseContent, response.toJson(), false);
            verifyRequestFor("insights", "full-request");
            assertTrue(
                    "response.getIpAddress().getCountry().isInEuropeanUnion() does not return true",
                    response.getIpAddress().getCountry().isInEuropeanUnion());
            assertFalse(
                    "response.getIpAddress().getRegisteredCountry().isInEuropeanUnion() does not return false",
                    response.getIpAddress().getRegisteredCountry().isInEuropeanUnion());
            assertTrue(
                    "response.getIpAddress().getRepresentedCountry().isInEuropeanUnion() does not return true",
                    response.getIpAddress().getRepresentedCountry().isInEuropeanUnion());
            assertEquals("2018-04-05T15:34:40-07:00", response.getDevice().getLocalTime());

            assertEquals("192.168.3.11", response.getIpAddress().getTraits().getIpAddress());
            assertEquals("172.16.58.3/24", response.getIpAddress().getTraits().getNetwork().toString());

            assertTrue(response.getCreditCard().isVirtual());
        }
    }

    @Test
    public void testFullFactorsTransaction() throws Exception {
        String responseContent = readJsonFile("factors-response");
        try (WebServiceClient client = createSuccessClient("factors", responseContent)) {
            Transaction request = fullTransaction();
            FactorsResponse response = client.factors(request);

            // We use non-strict checking as there is some extra stuff in the serialized
            // object, most notably the "name" field in the GeoIP2 InsightsResponse subobjects.
            // We cannot change this as it would be a breaking change to the GeoIP2 API.
            JSONAssert.assertEquals(responseContent, response.toJson(), false);
            verifyRequestFor("factors", "full-request");
            assertTrue(
                    "response.getIpAddress().getCountry().isInEuropeanUnion() does not return true",
                    response.getIpAddress().getCountry().isInEuropeanUnion());
            assertTrue(
                    "response.getIpAddress().getRegisteredCountry().isInEuropeanUnion() does not return true",
                    response.getIpAddress().getRegisteredCountry().isInEuropeanUnion());
            assertFalse(
                    "response.getIpAddress().getRepresentedCountry().isInEuropeanUnion() does not return false",
                    response.getIpAddress().getRepresentedCountry().isInEuropeanUnion());


            assertEquals("192.168.3.11", response.getIpAddress().getTraits().getIpAddress());
            assertEquals("172.16.58.3/24", response.getIpAddress().getTraits().getNetwork().toString());
        }
    }

    @Test
    public void testRequestEncoding() throws Exception {
        try (WebServiceClient client = createSuccessClient("insights", "{}")) {
            Transaction request = new Transaction.Builder(
                    new Device.Builder(InetAddress.getByName("1.1.1.1")).build()
            ).shipping(
                    new Shipping.Builder()
                            .firstName("<NAME> á s maia")
                            .build()
            ).build();
            client.insights(request);

            verify(postRequestedFor(urlMatching("/minfraud/v2.0/insights"))
                    .withRequestBody(equalToJson("{\"device\":{\"ip_address\":\"1.1.1.1\"},\"shipping\":{\"first_name\":\"<NAME> á s maia\"}}")));
        }
    }

    @Test
    public void test200WithNoBody() throws Exception {
        try (WebServiceClient client = createSuccessClient("insights", "")) {
            Transaction request = fullTransaction();
            Exception ex = assertThrows(MinFraudException.class, () -> client.insights(request));

            assertThat(ex.getMessage(), matchesPattern("Received a 200 response but could not decode it as JSON"));
        }
    }

    @Test
    public void test200WithInvalidJson() throws Exception {
        try (WebServiceClient client = createSuccessClient("insights", "{")) {
            Transaction request = fullTransaction();

            Exception ex = assertThrows(MinFraudException.class, () -> client.insights(request));

            assertEquals("Received a 200 response but could not decode it as JSON", ex.getMessage());
        }
    }

    @Test
    public void testInsufficientCredit() throws Exception {
        Exception ex = assertThrows(InsufficientFundsException.class, () -> {
            createInsightsError(
                    402,
                    "application/json",
                    "{\"code\":\"INSUFFICIENT_FUNDS\",\"error\":\"out of credit\"}"
            );
        });
        assertEquals("out of credit", ex.getMessage());

    }

    @Test
    @Parameters({"ACCOUNT_ID_REQUIRED",
            "AUTHORIZATION_INVALID",
            "LICENSE_KEY_REQUIRED",
            "USER_ID_REQUIRED"})
    public void testInvalidAuth(String code) throws Exception {
        Exception ex = assertThrows(AuthenticationException.class, () ->
                createInsightsError(
                        401,
                        "application/json",
                        "{\"code\":\"" + code + "\",\"error\":\"Invalid auth\"}"
                )
        );
        assertEquals("Invalid auth", ex.getMessage());
    }

    @Test
    public void testPermissionRequired() throws Exception {
        Exception ex = assertThrows(PermissionRequiredException.class, () -> {
            createInsightsError(
                    403,
                    "application/json",
                    "{\"code\":\"PERMISSION_REQUIRED\",\"error\":\"Permission required\"}"
            );
        });
        assertEquals("Permission required", ex.getMessage());
    }

    @Test
    public void testInvalidRequest() throws Exception {
        Exception ex = assertThrows(InvalidRequestException.class, () ->
                createInsightsError(
                        400,
                        "application/json",
                        "{\"code\":\"IP_ADDRESS_INVALID\",\"error\":\"IP invalid\"}"
                )
        );
        assertEquals("IP invalid", ex.getMessage());
    }

    @Test
    public void test400WithInvalidJson() throws Exception {
        Exception ex = assertThrows(HttpException.class, () ->
                createInsightsError(
                        400,<commit_msg>Minor code cleanup<commit_after>package com.maxmind.minfraud;

import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.maxmind.minfraud.exception.*;
import com.maxmind.minfraud.request.Device;
import com.maxmind.minfraud.request.Shipping;
import com.maxmind.minfraud.request.Transaction;
import com.maxmind.minfraud.response.FactorsResponse;
import com.maxmind.minfraud.response.InsightsResponse;
import com.maxmind.minfraud.response.ScoreResponse;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.skyscreamer.jsonassert.JSONAssert;

import java.net.InetAddress;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.jcabi.matchers.RegexMatchers.matchesPattern;
import static com.maxmind.minfraud.request.RequestTestHelper.*;
import static org.hamcrest.core.StringStartsWith.startsWith;
import static org.junit.Assert.*;
import static org.hamcrest.MatcherAssert.assertThat;

@RunWith(JUnitParamsRunner.class)
public class WebServiceClientTest {
    @Rule
    public final WireMockRule wireMockRule = new WireMockRule(0); // 0 picks random port

    @Test
    public void testFullScoreTransaction() throws Exception {
        String responseContent = readJsonFile("score-response");
        try (WebServiceClient client = createSuccessClient("score", responseContent)) {
            Transaction request = fullTransaction();
            ScoreResponse response = client.score(request);

            JSONAssert.assertEquals(responseContent, response.toJson(), true);
            verifyRequestFor("score", "full-request");
        }
    }

    @Test
    public void testFullScoreTransactionWithEmailMd5() throws Exception {
        String responseContent = readJsonFile("score-response");
        try (WebServiceClient client = createSuccessClient("score", responseContent)) {
            Transaction request = fullTransactionEmailMd5();
            ScoreResponse response = client.score(request);

            JSONAssert.assertEquals(responseContent, response.toJson(), true);
            verifyRequestFor("score", "full-request-email-md5");
        }
    }

    @Test
    public void testFullInsightsTransaction() throws Exception {
        String responseContent = readJsonFile("insights-response");
        try (WebServiceClient client = createSuccessClient("insights", responseContent)) {
            Transaction request = fullTransaction();
            InsightsResponse response = client.insights(request);

            // We use non-strict checking as there is some extra stuff in the serialized
            // object, most notably the "name" field in the GeoIP2 InsightsResponse subobjects.
            // We cannot change this as it would be a breaking change to the GeoIP2 API.
            JSONAssert.assertEquals(responseContent, response.toJson(), false);
            verifyRequestFor("insights", "full-request");
            assertTrue(
                    "response.getIpAddress().getCountry().isInEuropeanUnion() does not return true",
                    response.getIpAddress().getCountry().isInEuropeanUnion());
            assertFalse(
                    "response.getIpAddress().getRegisteredCountry().isInEuropeanUnion() does not return false",
                    response.getIpAddress().getRegisteredCountry().isInEuropeanUnion());
            assertTrue(
                    "response.getIpAddress().getRepresentedCountry().isInEuropeanUnion() does not return true",
                    response.getIpAddress().getRepresentedCountry().isInEuropeanUnion());
            assertEquals("2018-04-05T15:34:40-07:00", response.getDevice().getLocalTime());

            assertEquals("192.168.3.11", response.getIpAddress().getTraits().getIpAddress());
            assertEquals("172.16.58.3/24", response.getIpAddress().getTraits().getNetwork().toString());

            assertTrue(response.getCreditCard().isVirtual());
        }
    }

    @Test
    public void testFullFactorsTransaction() throws Exception {
        String responseContent = readJsonFile("factors-response");
        try (WebServiceClient client = createSuccessClient("factors", responseContent)) {
            Transaction request = fullTransaction();
            FactorsResponse response = client.factors(request);

            // We use non-strict checking as there is some extra stuff in the serialized
            // object, most notably the "name" field in the GeoIP2 InsightsResponse subobjects.
            // We cannot change this as it would be a breaking change to the GeoIP2 API.
            JSONAssert.assertEquals(responseContent, response.toJson(), false);
            verifyRequestFor("factors", "full-request");
            assertTrue(
                    "response.getIpAddress().getCountry().isInEuropeanUnion() does not return true",
                    response.getIpAddress().getCountry().isInEuropeanUnion());
            assertTrue(
                    "response.getIpAddress().getRegisteredCountry().isInEuropeanUnion() does not return true",
                    response.getIpAddress().getRegisteredCountry().isInEuropeanUnion());
            assertFalse(
                    "response.getIpAddress().getRepresentedCountry().isInEuropeanUnion() does not return false",
                    response.getIpAddress().getRepresentedCountry().isInEuropeanUnion());


            assertEquals("192.168.3.11", response.getIpAddress().getTraits().getIpAddress());
            assertEquals("172.16.58.3/24", response.getIpAddress().getTraits().getNetwork().toString());
        }
    }

    @Test
    public void testRequestEncoding() throws Exception {
        try (WebServiceClient client = createSuccessClient("insights", "{}")) {
            Transaction request = new Transaction.Builder(
                    new Device.Builder(InetAddress.getByName("1.1.1.1")).build()
            ).shipping(
                    new Shipping.Builder()
                            .firstName("All<NAME> á s maia")
                            .build()
            ).build();
            client.insights(request);

            verify(postRequestedFor(urlMatching("/minfraud/v2.0/insights"))
                    .withRequestBody(equalToJson("{\"device\":{\"ip_address\":\"1.1.1.1\"},\"shipping\":{\"first_name\":\"<NAME> á s maia\"}}")));
        }
    }

    @Test
    public void test200WithNoBody() throws Exception {
        try (WebServiceClient client = createSuccessClient("insights", "")) {
            Transaction request = fullTransaction();
            Exception ex = assertThrows(MinFraudException.class, () -> client.insights(request));

            assertThat(ex.getMessage(), matchesPattern("Received a 200 response but could not decode it as JSON"));
        }
    }

    @Test
    public void test200WithInvalidJson() throws Exception {
        try (WebServiceClient client = createSuccessClient("insights", "{")) {
            Transaction request = fullTransaction();

            Exception ex = assertThrows(MinFraudException.class, () -> client.insights(request));

            assertEquals("Received a 200 response but could not decode it as JSON", ex.getMessage());
        }
    }

    @Test
    public void testInsufficientCredit() throws Exception {
        Exception ex = assertThrows(InsufficientFundsException.class, () -> createInsightsError(
                402,
                "application/json",
                "{\"code\":\"INSUFFICIENT_FUNDS\",\"error\":\"out of credit\"}"
        ));
        assertEquals("out of credit", ex.getMessage());

    }

    @Test
    @Parameters({"ACCOUNT_ID_REQUIRED",
            "AUTHORIZATION_INVALID",
            "LICENSE_KEY_REQUIRED",
            "USER_ID_REQUIRED"})
    public void testInvalidAuth(String code) throws Exception {
        Exception ex = assertThrows(AuthenticationException.class, () ->
                createInsightsError(
                        401,
                        "application/json",
                        "{\"code\":\"" + code + "\",\"error\":\"Invalid auth\"}"
                )
        );
        assertEquals("Invalid auth", ex.getMessage());
    }

    @Test
    public void testPermissionRequired() throws Exception {
        Exception ex = assertThrows(PermissionRequiredException.class, () -> createInsightsError(
                403,
                "application/json",
                "{\"code\":\"PERMISSION_REQUIRED\",\"error\":\"Permission required\"}"
        ));
        assertEquals("Permission required", ex.getMessage());
    }

    @Test
    public void testInvalidRequest() throws Exception {
        Exception ex = assertThrows(InvalidRequestException.class, () ->
                createInsightsError(
                        400,
                        "application/json",
                        "{\"code\":\"IP_ADDRESS_INVALID\",\"error\":\"IP invalid\"}"
                )
        );
        assertEquals("IP invalid", ex.getMessage());
    }

    @Test
    public void test400WithInvalidJson() throws Exception {
        Exception ex = assertThrows(HttpException.class, () ->
                createInsightsError(
                        400,
{'fraction_non_alphanumeric': 0.1136707765520225, 'fraction_numerical': 0.01135626216742375, 'mean_word_length': 2.562512040069351, 'pattern_counts': {'":': 24, '<': 7, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 12, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3225949', 'n_tokens_mistral': 4736, 'n_tokens_neox': 4475, 'n_words': 951}