/*
 * Jooby https://jooby.io
 * Apache License Version 2.0 https://jooby.io/LICENSE.txt
 * Copyright 2014 Edgar Espina
 */
package io.jooby;

import static com.typesafe.config.ConfigValueFactory.fromAnyRef;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.time.Duration;
import java.util.Arrays;
import java.util.function.Consumer;

import org.junit.jupiter.api.Test;

import com.google.common.collect.Lists;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import io.jooby.handler.Cors;

public class CorsTest {

  @Test
  public void defaults() {
    cors(
        cors -> {
          assertEquals(true, cors.anyOrigin());
          assertEquals(Arrays.asList("*"), cors.getOrigin());
          assertEquals(true, cors.getUseCredentials());

          assertEquals(true, cors.allowMethod("get"));
          assertEquals(true, cors.allowMethod("post"));
          assertEquals(Arrays.asList("GET", "POST"), cors.getMethods());

          assertEquals(true, cors.allowHeader("X-Requested-With"));
          assertEquals(true, cors.allowHeader("Content-Type"));
          assertEquals(true, cors.allowHeader("Accept"));
          assertEquals(true, cors.allowHeader("Origin"));
          assertEquals(
              true, cors.allowHeader("X-Requested-With", "Content-Type", "Accept", "Origin"));
          assertEquals(
              Arrays.asList("X-Requested-With", "Content-Type", "Accept", "Origin"),
              cors.getHeaders());

          assertEquals(Duration.ofMinutes(30), cors.getMaxAge());

          assertEquals(Arrays.asList(), cors.getExposedHeaders());

          assertEquals(false, cors.setUseCredentials(false).getUseCredentials());
        });
  }

  @Test
  public void origin() {
    cors(
        baseconf().withValue("origin", fromAnyRef("*")),
        cors -> {
          assertEquals(true, cors.anyOrigin());
          assertEquals(true, cors.allowOrigin("http://foo.com"));
        });

    cors(
        baseconf().withValue("origin", fromAnyRef("http://*.com")),
        cors -> {
          assertEquals(false, cors.anyOrigin());
          assertEquals(true, cors.allowOrigin("http://foo.com"));
          assertEquals(true, cors.allowOrigin("http://bar.com"));
        });

    cors(
        baseconf().withValue("origin", fromAnyRef("http://foo.com")),
        cors -> {
          assertEquals(false, cors.anyOrigin());
          assertEquals(true, cors.allowOrigin("http://foo.com"));
          assertEquals(false, cors.allowOrigin("http://bar.com"));
        });
  }

  @Test
  public void allowedMethods() {
    cors(
        baseconf().withValue("methods", fromAnyRef("GET")),
        cors -> {
          assertEquals(true, cors.allowMethod("GET"));
          assertEquals(true, cors.allowMethod("get"));
          assertEquals(false, cors.allowMethod("POST"));
        });

    cors(
        baseconf().withValue("methods", fromAnyRef(asList("get", "post"))),
        cors -> {
          assertEquals(true, cors.allowMethod("GET"));
          assertEquals(true, cors.allowMethod("get"));
          assertEquals(true, cors.allowMethod("POST"));
        });
  }

  @Test
  public void requestHeaders() {
    cors(
        baseconf().withValue("headers", fromAnyRef("*")),
        cors -> {
          assertEquals(true, cors.anyHeader());
          assertEquals(true, cors.allowHeader("Custom-Header"));
        });

    cors(
        baseconf().withValue("headers", fromAnyRef(asList("X-Requested-With", "*"))),
        cors -> {
          assertEquals(true, cors.allowHeader("X-Requested-With"));
          assertEquals(true, cors.anyHeader());
        });

    cors(
        baseconf()
            .withValue(
                "headers",
                fromAnyRef(asList("X-Requested-With", "Content-Type", "Accept", "Origin"))),
        cors -> {
          assertEquals(false, cors.anyHeader());
          assertEquals(true, cors.allowHeader("X-Requested-With"));
          assertEquals(true, cors.allowHeader("Content-Type"));
          assertEquals(true, cors.allowHeader("Accept"));
          assertEquals(true, cors.allowHeader("Origin"));
          assertEquals(
              true,
              cors.allowHeaders(asList("X-Requested-With", "Content-Type", "Accept", "Origin")));
          assertEquals(
              false, cors.allowHeaders(asList("X-Requested-With", "Content-Type", "Custom")));
        });
  }

  private void cors(final Config conf, final Consumer<Cors> callback) {
    callback.accept(Cors.from(conf));
  }

  private void cors(final Consumer<Cors> callback) {
    callback.accept(new Cors());
  }

  private Config baseconf() {
    return ConfigFactory.empty()
        .withValue("credentials", fromAnyRef(true))
        .withValue("maxAge", fromAnyRef("30m"))
        .withValue("origin", fromAnyRef(Lists.newArrayList()))
        .withValue("exposedHeaders", fromAnyRef(Lists.newArrayList("X")))
        .withValue("methods", fromAnyRef(Lists.newArrayList()))
        .withValue("headers", fromAnyRef(Lists.newArrayList()));
  }
}
