/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.servicecomb.foundation.common.http;

import java.net.URISyntaxException;

import jakarta.ws.rs.core.MediaType;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class TestHttpUtils {

  @Test
  public void parseParamFromHeaderValue_normal() {
    Assertions.assertEquals("a", HttpUtils.parseParamFromHeaderValue("key1=a;key2=b", "key1"));
    Assertions.assertEquals("b", HttpUtils.parseParamFromHeaderValue("key1=a;key2= b", "key2"));
    Assertions.assertEquals("b", HttpUtils.parseParamFromHeaderValue("key1=a; key2=b", "key2"));
    Assertions.assertEquals("a", HttpUtils.parseParamFromHeaderValue("key1=\"a\";key2=\"b\"", "key1"));
    Assertions.assertEquals("b", HttpUtils.parseParamFromHeaderValue("key1=\"a\";key2=\" b\"", "key2"));
    Assertions.assertEquals("b", HttpUtils.parseParamFromHeaderValue("key1=\"a\"; key2=\"b\"", "key2"));
    Assertions.assertEquals("b c.txt", HttpUtils.parseParamFromHeaderValue("key1=\"a\"; key2=\"b c.txt\"", "key2"));
  }

  @Test
  public void parseParamFromHeaderValue_null() {
    Assertions.assertNull(HttpUtils.parseParamFromHeaderValue(null, "key"));
    Assertions.assertNull(HttpUtils.parseParamFromHeaderValue("key1=a; key2=b", "key"));
  }

  @Test
  public void parseParamFromHeaderValue_emptyStr() {
    Assertions.assertEquals("", HttpUtils.parseParamFromHeaderValue("key1=a; key2=", "key2"));
  }

  @Test
  public void uriEncode_null() {
    Assertions.assertEquals("", HttpUtils.uriEncodePath(null));
  }

  @Test
  public void uriDecode_null() {
    Assertions.assertNull(HttpUtils.uriDecodePath(null));
  }

  @Test
  public void uriEncode_chineseAndSpace() {
    String encoded = HttpUtils.uriEncodePath("测 试");
    Assertions.assertEquals("%E6%B5%8B%20%E8%AF%95", encoded);
    Assertions.assertEquals("测 试", HttpUtils.uriDecodePath(encoded));
  }

  @Test
  public void uriEncode_failed() {
    IllegalArgumentException illegalArgumentException = Assertions.assertThrows(IllegalArgumentException.class,
        () -> HttpUtils.uriEncodePath(":"));
    Assertions.assertEquals("uriEncode failed, path=\":\".", illegalArgumentException.getMessage());
    Assertions.assertTrue(illegalArgumentException.getCause() instanceof URISyntaxException);
  }

  @Test
  public void uriEncode_plus() {
    String encoded = HttpUtils.uriEncodePath("a+b");
    Assertions.assertEquals("a+b", encoded);
    Assertions.assertEquals("a+b", HttpUtils.uriDecodePath(encoded));
  }

  @Test
  public void uriEncode_encodeEntirePath() {
    String encoded = HttpUtils.uriEncodePath("a%%'+b/def");
    Assertions.assertEquals("a%25%25'+b/def", encoded);
  }

  @Test
  public void pathParamEncode() {
    Assertions.assertEquals("a+b", HttpUtils.encodePathParam("a+b"));
    Assertions.assertEquals("a%25b", HttpUtils.encodePathParam("a%b"));
    Assertions.assertEquals("a%25%25b", HttpUtils.encodePathParam("a%%b"));
    Assertions.assertEquals("%3C%20%3E'%22%EF%BC%88)&%2F%20%20", HttpUtils.encodePathParam("< >'\"（)&/  "));
    Assertions.assertEquals("%E6%B5%8B%20%E8%AF%95", HttpUtils.encodePathParam("测 试"));
  }

  /**
   * SafeChar: the characters that are not encoded.
   * This test is to show those safe chars excepting 0..9, a..z and A..Z
   */
  @Test
  public void pathParamEncode_SafeChar() {
    Assertions.assertEquals("-._~!$'()*,;&=@:+", HttpUtils.encodePathParam("-._~!$'()*,;&=@:+"));
  }

  @Test
  public void uriDecode_failed() {
    IllegalArgumentException illegalArgumentException = Assertions.assertThrows(IllegalArgumentException.class,
        () -> HttpUtils.uriDecodePath(":"));
    Assertions.assertEquals("uriDecode failed, path=\":\".", illegalArgumentException.getMessage());
    Assertions.assertTrue(illegalArgumentException.getCause() instanceof URISyntaxException);
  }

  @Test
  public void parseFileNameFromHeaderValue() {
    String fileName = "测 试.txt";
    String encoded = HttpUtils.uriEncodePath(fileName);
    Assertions.assertEquals(fileName, HttpUtils.parseFileNameFromHeaderValue("xx;filename=" + encoded));
  }

  @Test
  public void parseFileNameFromHeaderValue_defaultName() {
    Assertions.assertEquals("default", HttpUtils.parseFileNameFromHeaderValue("xx"));
  }

  @Test
  public void parseFileNameFromHeaderValue_ignorePath() {
    Assertions.assertEquals("a.txt", HttpUtils.parseFileNameFromHeaderValue("xx;filename=../../a.txt"));
  }

  @Test
  public void getCharsetFromContentType_noContentType() {
    String character = HttpUtils.getCharsetFromContentType(null);

    Assertions.assertNull(character);
  }

  @Test
  public void getCharsetFromContentType_noCharset() {
    String character = HttpUtils.getCharsetFromContentType(MediaType.APPLICATION_JSON);

    Assertions.assertNull(character);
  }

  @Test
  public void getCharsetFromContentType_noSemicolonEnd() {
    String character = HttpUtils.getCharsetFromContentType(MediaType.APPLICATION_JSON + ";charset=utf-8");

    Assertions.assertEquals("utf-8", character);
  }

  @Test
  public void getCharsetFromContentType_semicolonEnd() {
    String character = HttpUtils.getCharsetFromContentType(MediaType.APPLICATION_JSON + ";charset=utf-8;");

    Assertions.assertEquals("utf-8", character);
  }

  @Test
  public void getCharsetFromContentType_needTrim() {
    String character = HttpUtils.getCharsetFromContentType(MediaType.APPLICATION_JSON + ";charset= utf-8 ;");

    Assertions.assertEquals("utf-8", character);
  }

  @Test
  public void getCharsetFromContentType_quotationMarks() {
    String character = HttpUtils.getCharsetFromContentType(MediaType.APPLICATION_JSON + ";charset=\"utf-8\";");

    Assertions.assertEquals("utf-8", character);
  }

  @Test
  public void getCharsetFromContentType_quotationMarks_needTrim() {
    String character = HttpUtils.getCharsetFromContentType(MediaType.APPLICATION_JSON + ";charset=\" utf-8 \";");

    Assertions.assertEquals("utf-8", character);
  }

  @Test
  public void splitPath() {
    Assertions.assertNull(HttpUtils.splitPathFromUri(null));
    Assertions.assertEquals("", HttpUtils.splitPathFromUri(""));
    Assertions.assertEquals(" ", HttpUtils.splitPathFromUri(" "));
    Assertions.assertEquals("\t", HttpUtils.splitPathFromUri("\t"));
    Assertions.assertEquals("/", HttpUtils.splitPathFromUri("/"));
    Assertions.assertEquals("//", HttpUtils.splitPathFromUri("//"));
    Assertions.assertEquals("/abc", HttpUtils.splitPathFromUri("/abc"));
    Assertions.assertEquals("//abc", HttpUtils.splitPathFromUri("//abc"));
    Assertions.assertEquals("abc", HttpUtils.splitPathFromUri("abc"));
    Assertions.assertEquals("a/bc", HttpUtils.splitPathFromUri("a/bc"));
    Assertions.assertEquals("/a/bc", HttpUtils.splitPathFromUri("/a/bc"));
    Assertions.assertEquals("", HttpUtils.splitPathFromUri("?abc=def"));

    Assertions.assertEquals("/", HttpUtils.splitPathFromUri("http://localhost"));
    Assertions.assertEquals("/", HttpUtils.splitPathFromUri("http://localhost "));
    Assertions.assertEquals("/", HttpUtils.splitPathFromUri("http://localhost\t"));
    Assertions.assertEquals("/", HttpUtils.splitPathFromUri("http://localhost/"));
    Assertions.assertEquals("//", HttpUtils.splitPathFromUri("http://localhost//"));
    Assertions.assertEquals("/abc", HttpUtils.splitPathFromUri("http://localhost/abc"));
    Assertions.assertEquals("/a/bc", HttpUtils.splitPathFromUri("http://localhost/a/bc"));
    Assertions.assertEquals("/abc", HttpUtils.splitPathFromUri("http://localhost/abc?"));
    Assertions.assertEquals("/abc", HttpUtils.splitPathFromUri("http://localhost/abc?k=v"));
    Assertions.assertEquals("/a/bc", HttpUtils.splitPathFromUri("http://localhost/a/bc?k=v"));

    Assertions.assertEquals("/", HttpUtils.splitPathFromUri("rest://localhost:80"));
    Assertions.assertEquals("/", HttpUtils.splitPathFromUri("rest://localhost:80 "));
    Assertions.assertEquals("/", HttpUtils.splitPathFromUri("rest://localhost:80\t"));
    Assertions.assertEquals("/", HttpUtils.splitPathFromUri("rest://localhost:80/"));
    Assertions.assertEquals("//", HttpUtils.splitPathFromUri("rest://localhost:80//"));
    Assertions.assertEquals("/abc", HttpUtils.splitPathFromUri("rest://localhost:80/abc"));
    Assertions.assertEquals("/a/bc", HttpUtils.splitPathFromUri("rest://localhost:80/a/bc"));
    Assertions.assertEquals("/abc", HttpUtils.splitPathFromUri("rest://localhost:80/abc?"));
    Assertions.assertEquals("/a/bc", HttpUtils.splitPathFromUri("rest://localhost:80/a/bc?"));
    Assertions.assertEquals("/abc", HttpUtils.splitPathFromUri("rest://localhost:80/abc?k=v&m=n"));
  }

  @Test
  public void splitQuery() {
    Assertions.assertNull(HttpUtils.splitQueryFromUri(null));
    Assertions.assertNull(HttpUtils.splitQueryFromUri(""));
    Assertions.assertNull(HttpUtils.splitQueryFromUri(" "));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("\t"));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("/"));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("//"));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("/abc"));
    Assertions.assertEquals("", HttpUtils.splitQueryFromUri("/abc?"));
    Assertions.assertEquals("k=v", HttpUtils.splitQueryFromUri("/abc?k=v"));
    Assertions.assertEquals("k=v&m=n", HttpUtils.splitQueryFromUri("/abc?k=v&m=n"));

    Assertions.assertNull(HttpUtils.splitQueryFromUri("http://localhost"));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("http://localhost "));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("http://localhost\t"));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("http://localhost/"));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("http://localhost//"));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("http://localhost/abc"));
    Assertions.assertEquals("", HttpUtils.splitQueryFromUri("http://localhost/abc?"));
    Assertions.assertEquals("k=v", HttpUtils.splitQueryFromUri("http://localhost/abc?k=v"));
    Assertions.assertEquals("k=v&m=n", HttpUtils.splitQueryFromUri("http://localhost/abc?k=v&m=n"));

    Assertions.assertNull(HttpUtils.splitQueryFromUri("http://localhost:80"));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("http://localhost:80 "));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("http://localhost:80\t"));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("http://localhost:80/"));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("http://localhost:80//"));
    Assertions.assertNull(HttpUtils.splitQueryFromUri("http://localhost:80/abc"));
    Assertions.assertEquals("", HttpUtils.splitQueryFromUri("http://localhost:80/abc?"));
    Assertions.assertEquals("k=v", HttpUtils.splitQueryFromUri("http://localhost:80/abc?k=v"));
    Assertions.assertEquals("k=v&m=n", HttpUtils.splitQueryFromUri("http://localhost:80/abc?k=v&m=n"));
  }
}
