// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Mobius Forensic Toolkit
// Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 Eduardo Aguiar
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <mobius/unittest.h>
#include <mobius/uri.h>

static const std::string
join (const mobius::uri& base, const std::string& rel)
{
  mobius::uri target = join (base, mobius::uri (rel));
  return target.get_value ();
}

static void
testcase_uri ()
{
  mobius::unittest test ("mobius::uri");

  // examples from RFC 3986 - section 1.1.2
  mobius::uri uri1 ("ftp://ftp.is.co.za/rfc/rfc1808.txt");
  mobius::uri uri2 ("http://www.ietf.org/rfc/rfc2396.txt");
  mobius::uri uri3 ("ldap://[2001:db8::7]/c=GB?objectClass?one");
  mobius::uri uri4 ("mailto:John.Doe@example.com");
  mobius::uri uri5 ("news:comp.infosystems.www.servers.unix");
  mobius::uri uri6 ("tel:+1-816-555-1212");
  mobius::uri uri7 ("telnet://192.0.2.16:80/");
  mobius::uri uri8 ("urn:oasis:names:specification:docbook:dtd:xml:4.1.2");

  // copy constructor and copy assignment
  mobius::uri uri_c1 = uri2;
  mobius::uri uri_c2;
  uri_c2 = uri2;

  // URI build from its parts
  mobius::uri uri9;
  uri9.set_scheme ("https");
  uri9.set_authority ("aguiar:mypassword@www.gnu.org:80");
  uri9.set_path ("/test/subdir 1");
  uri9.set_query ("value=55&p=#14");
  uri9.set_fragment ("anchor1");

  // full URI
  mobius::uri uri10 ("https://aguiar:mypassword@www.gnu.org:80/test/subdir%201?value=55#anchor1");

  // copy constructor and copy assignment
  test.ASSERT_EQUAL (uri_c1, uri2);
  test.ASSERT_EQUAL (uri_c2, uri2);
  test.ASSERT_NOT_EQUAL (uri1, uri2);

  // empty URI
  mobius::uri uri11;

  // value
  test.ASSERT_EQUAL (uri1.get_value (), "ftp://ftp.is.co.za/rfc/rfc1808.txt");
  test.ASSERT_EQUAL (uri2.get_value (), "http://www.ietf.org/rfc/rfc2396.txt");
  test.ASSERT_EQUAL (uri3.get_value (), "ldap://[2001:db8::7]/c=GB?objectClass?one");
  test.ASSERT_EQUAL (uri4.get_value (), "mailto:John.Doe@example.com");
  test.ASSERT_EQUAL (uri5.get_value (), "news:comp.infosystems.www.servers.unix");
  test.ASSERT_EQUAL (uri6.get_value (), "tel:+1-816-555-1212");
  test.ASSERT_EQUAL (uri7.get_value (), "telnet://192.0.2.16:80/");
  test.ASSERT_EQUAL (uri8.get_value (), "urn:oasis:names:specification:docbook:dtd:xml:4.1.2");
  test.ASSERT_EQUAL (uri9.get_value (), "https://aguiar:mypassword@www.gnu.org:80/test/subdir%201?value=55&p=%2314#anchor1");
  test.ASSERT_EQUAL (uri10.get_value (), "https://aguiar:mypassword@www.gnu.org:80/test/subdir%201?value=55#anchor1");

  // is_empty
  test.ASSERT_FALSE (uri1.is_empty ());
  test.ASSERT_FALSE (uri2.is_empty ());
  test.ASSERT_FALSE (uri3.is_empty ());
  test.ASSERT_FALSE (uri4.is_empty ());
  test.ASSERT_FALSE (uri5.is_empty ());
  test.ASSERT_FALSE (uri6.is_empty ());
  test.ASSERT_FALSE (uri7.is_empty ());
  test.ASSERT_FALSE (uri8.is_empty ());
  test.ASSERT_FALSE (uri9.is_empty ());
  test.ASSERT_FALSE (uri10.is_empty ());
  test.ASSERT_TRUE (uri11.is_empty ());

  // is_relative
  test.ASSERT_FALSE (uri1.is_relative ());
  test.ASSERT_FALSE (uri2.is_relative ());
  test.ASSERT_FALSE (uri3.is_relative ());
  test.ASSERT_FALSE (uri4.is_relative ());
  test.ASSERT_FALSE (uri5.is_relative ());
  test.ASSERT_FALSE (uri6.is_relative ());
  test.ASSERT_FALSE (uri7.is_relative ());
  test.ASSERT_FALSE (uri8.is_relative ());
  test.ASSERT_FALSE (uri9.is_relative ());
  test.ASSERT_FALSE (uri10.is_relative ());
  test.ASSERT_FALSE (uri11.is_relative ());

  // is_absolute
  test.ASSERT_TRUE (uri1.is_absolute ());
  test.ASSERT_TRUE (uri2.is_absolute ());
  test.ASSERT_TRUE (uri3.is_absolute ());
  test.ASSERT_TRUE (uri4.is_absolute ());
  test.ASSERT_TRUE (uri5.is_absolute ());
  test.ASSERT_TRUE (uri6.is_absolute ());
  test.ASSERT_TRUE (uri7.is_absolute ());
  test.ASSERT_TRUE (uri8.is_absolute ());
  test.ASSERT_FALSE (uri9.is_absolute ());
  test.ASSERT_FALSE (uri10.is_absolute ());
  test.ASSERT_FALSE (uri11.is_absolute ());

  // scheme
  test.ASSERT_EQUAL (uri1.get_scheme (), "ftp");
  test.ASSERT_EQUAL (uri2.get_scheme (), "http");
  test.ASSERT_EQUAL (uri3.get_scheme (), "ldap");
  test.ASSERT_EQUAL (uri4.get_scheme (), "mailto");
  test.ASSERT_EQUAL (uri5.get_scheme (), "news");
  test.ASSERT_EQUAL (uri6.get_scheme (), "tel");
  test.ASSERT_EQUAL (uri7.get_scheme (), "telnet");
  test.ASSERT_EQUAL (uri8.get_scheme (), "urn");
  test.ASSERT_EQUAL (uri9.get_scheme (), "https");
  test.ASSERT_EQUAL (uri10.get_scheme (), "https");

  // authority
  test.ASSERT_EQUAL (uri1.get_authority (), "ftp.is.co.za");
  test.ASSERT_EQUAL (uri2.get_authority (), "www.ietf.org");
  test.ASSERT_EQUAL (uri3.get_authority (), "[2001:db8::7]");
  test.ASSERT_EQUAL (uri4.get_authority (), "");
  test.ASSERT_EQUAL (uri5.get_authority (), "");
  test.ASSERT_EQUAL (uri6.get_authority (), "");
  test.ASSERT_EQUAL (uri7.get_authority (), "192.0.2.16:80");
  test.ASSERT_EQUAL (uri8.get_authority (), "");
  test.ASSERT_EQUAL (uri9.get_authority (), "aguiar:mypassword@www.gnu.org:80");
  test.ASSERT_EQUAL (uri10.get_authority (), "aguiar:mypassword@www.gnu.org:80");

  // path
  test.ASSERT_EQUAL (uri1.get_path (), "/rfc/rfc1808.txt");
  test.ASSERT_EQUAL (uri2.get_path (), "/rfc/rfc2396.txt");
  test.ASSERT_EQUAL (uri3.get_path (), "/c=GB");
  test.ASSERT_EQUAL (uri4.get_path (), "John.Doe@example.com");
  test.ASSERT_EQUAL (uri5.get_path (), "comp.infosystems.www.servers.unix");
  test.ASSERT_EQUAL (uri6.get_path (), "+1-816-555-1212");
  test.ASSERT_EQUAL (uri7.get_path (), "/");
  test.ASSERT_EQUAL (uri8.get_path (), "oasis:names:specification:docbook:dtd:xml:4.1.2");
  test.ASSERT_EQUAL (uri9.get_path (), "/test/subdir 1");
  test.ASSERT_EQUAL (uri10.get_path (), "/test/subdir 1");

  // query
  test.ASSERT_EQUAL (uri1.get_query (), "");
  test.ASSERT_EQUAL (uri2.get_query (), "");
  test.ASSERT_EQUAL (uri3.get_query (), "objectClass?one");
  test.ASSERT_EQUAL (uri4.get_query (), "");
  test.ASSERT_EQUAL (uri5.get_query (), "");
  test.ASSERT_EQUAL (uri6.get_query (), "");
  test.ASSERT_EQUAL (uri7.get_query (), "");
  test.ASSERT_EQUAL (uri8.get_query (), "");
  test.ASSERT_EQUAL (uri9.get_query (), "value=55&p=#14");
  test.ASSERT_EQUAL (uri10.get_query (), "value=55");

  // fragment
  test.ASSERT_EQUAL (uri1.get_fragment (), "");
  test.ASSERT_EQUAL (uri2.get_fragment (), "");
  test.ASSERT_EQUAL (uri3.get_fragment (), "");
  test.ASSERT_EQUAL (uri4.get_fragment (), "");
  test.ASSERT_EQUAL (uri5.get_fragment (), "");
  test.ASSERT_EQUAL (uri6.get_fragment (), "");
  test.ASSERT_EQUAL (uri7.get_fragment (), "");
  test.ASSERT_EQUAL (uri8.get_fragment (), "");
  test.ASSERT_EQUAL (uri9.get_fragment (), "anchor1");
  test.ASSERT_EQUAL (uri10.get_fragment (), "anchor1");

  // username
  test.ASSERT_EQUAL (uri1.get_username (), "");
  test.ASSERT_EQUAL (uri2.get_username (), "");
  test.ASSERT_EQUAL (uri3.get_username (), "");
  test.ASSERT_EQUAL (uri4.get_username (), "");
  test.ASSERT_EQUAL (uri5.get_username (), "");
  test.ASSERT_EQUAL (uri6.get_username (), "");
  test.ASSERT_EQUAL (uri7.get_username (), "");
  test.ASSERT_EQUAL (uri8.get_username (), "");
  test.ASSERT_EQUAL (uri9.get_username (), "aguiar");
  test.ASSERT_EQUAL (uri10.get_username (), "aguiar");

  // password
  test.ASSERT_EQUAL (uri1.get_password (), "");
  test.ASSERT_EQUAL (uri2.get_password (), "");
  test.ASSERT_EQUAL (uri3.get_password (), "");
  test.ASSERT_EQUAL (uri4.get_password (), "");
  test.ASSERT_EQUAL (uri5.get_password (), "");
  test.ASSERT_EQUAL (uri6.get_password (), "");
  test.ASSERT_EQUAL (uri7.get_password (), "");
  test.ASSERT_EQUAL (uri8.get_password (), "");
  test.ASSERT_EQUAL (uri9.get_password (), "mypassword");
  test.ASSERT_EQUAL (uri10.get_password (), "mypassword");

  // host
  test.ASSERT_EQUAL (uri1.get_host (), "ftp.is.co.za");
  test.ASSERT_EQUAL (uri2.get_host (), "www.ietf.org");
  test.ASSERT_EQUAL (uri3.get_host (), "[2001:db8::7]");
  test.ASSERT_EQUAL (uri4.get_host (), "");
  test.ASSERT_EQUAL (uri5.get_host (), "");
  test.ASSERT_EQUAL (uri6.get_host (), "");
  test.ASSERT_EQUAL (uri7.get_host (), "192.0.2.16");
  test.ASSERT_EQUAL (uri8.get_host (), "");
  test.ASSERT_EQUAL (uri9.get_host (), "www.gnu.org");
  test.ASSERT_EQUAL (uri10.get_host (), "www.gnu.org");

  // port
  test.ASSERT_EQUAL (uri1.get_port (), "");
  test.ASSERT_EQUAL (uri2.get_port (), "");
  test.ASSERT_EQUAL (uri3.get_port (), "");
  test.ASSERT_EQUAL (uri4.get_port (), "");
  test.ASSERT_EQUAL (uri5.get_port (), "");
  test.ASSERT_EQUAL (uri6.get_port (), "");
  test.ASSERT_EQUAL (uri7.get_port (), "80");
  test.ASSERT_EQUAL (uri8.get_port (), "");
  test.ASSERT_EQUAL (uri9.get_port (), "80");
  test.ASSERT_EQUAL (uri10.get_port (), "80");

  // dirname
  test.ASSERT_EQUAL (uri1.get_dirname (), "ftp://ftp.is.co.za/rfc");
  test.ASSERT_EQUAL (uri2.get_dirname (), "http://www.ietf.org/rfc");
  test.ASSERT_EQUAL (uri3.get_dirname (), "ldap://[2001:db8::7]");
  test.ASSERT_EQUAL (uri4.get_dirname (), "");
  test.ASSERT_EQUAL (uri5.get_dirname (), "");
  test.ASSERT_EQUAL (uri6.get_dirname (), "");
  test.ASSERT_EQUAL (uri7.get_dirname (), "telnet://192.0.2.16:80");
  test.ASSERT_EQUAL (uri8.get_dirname (), "");
  test.ASSERT_EQUAL (uri9.get_dirname (), "https://aguiar:mypassword@www.gnu.org:80/test");
  test.ASSERT_EQUAL (uri10.get_dirname (), "https://aguiar:mypassword@www.gnu.org:80/test");

  // basename
  test.ASSERT_EQUAL (uri1.get_basename (), "rfc1808.txt");
  test.ASSERT_EQUAL (uri2.get_basename (), "rfc2396.txt");
  test.ASSERT_EQUAL (uri3.get_basename (), "c=GB");
  test.ASSERT_EQUAL (uri4.get_basename (), "");
  test.ASSERT_EQUAL (uri5.get_basename (), "");
  test.ASSERT_EQUAL (uri6.get_basename (), "");
  test.ASSERT_EQUAL (uri7.get_basename (), "");
  test.ASSERT_EQUAL (uri8.get_basename (), "");
  test.ASSERT_EQUAL (uri9.get_basename (), "subdir 1");
  test.ASSERT_EQUAL (uri10.get_basename (), "subdir 1");

  // extension
  test.ASSERT_EQUAL (uri1.get_extension (), "txt");
  test.ASSERT_EQUAL (uri2.get_extension (), "txt");
  test.ASSERT_EQUAL (uri3.get_extension (), "");
  test.ASSERT_EQUAL (uri4.get_extension (), "com");
  test.ASSERT_EQUAL (uri5.get_extension (), "unix");
  test.ASSERT_EQUAL (uri6.get_extension (), "");
  test.ASSERT_EQUAL (uri7.get_extension (), "");
  test.ASSERT_EQUAL (uri8.get_extension (), "2");
  test.ASSERT_EQUAL (uri9.get_extension (), "");
  test.ASSERT_EQUAL (uri10.get_extension (), "");

  // join - normal examples - RFC 3986 - section 5.4.1
  mobius::uri base ("http://a/b/c/d;p?q");

  test.ASSERT_EQUAL (join (base, "g:h"), "g:h");
  test.ASSERT_EQUAL (join (base, "g"), "http://a/b/c/g");
  test.ASSERT_EQUAL (join (base, "./g"), "http://a/b/c/g");
  test.ASSERT_EQUAL (join (base, "g/"), "http://a/b/c/g/");
  test.ASSERT_EQUAL (join (base, "/g"), "http://a/g");
  test.ASSERT_EQUAL (join (base, "//g"), "http://g");
  test.ASSERT_EQUAL (join (base, "?y"), "http://a/b/c/d;p?y");
  test.ASSERT_EQUAL (join (base, "g?y"), "http://a/b/c/g?y");
  test.ASSERT_EQUAL (join (base, "#s"), "http://a/b/c/d;p?q#s");
  test.ASSERT_EQUAL (join (base, "g#s"), "http://a/b/c/g#s");
  test.ASSERT_EQUAL (join (base, "g?y#s"), "http://a/b/c/g?y#s");
  test.ASSERT_EQUAL (join (base, ";x"), "http://a/b/c/;x");
  test.ASSERT_EQUAL (join (base, "g;x"), "http://a/b/c/g;x");
  test.ASSERT_EQUAL (join (base, "g;x?y#s"), "http://a/b/c/g;x?y#s");
  test.ASSERT_EQUAL (join (base, ""), "http://a/b/c/d;p?q");
  test.ASSERT_EQUAL (join (base, "."), "http://a/b/c/");
  test.ASSERT_EQUAL (join (base, "./"), "http://a/b/c/");
  test.ASSERT_EQUAL (join (base, ".."), "http://a/b/");
  test.ASSERT_EQUAL (join (base, "../"), "http://a/b/");
  test.ASSERT_EQUAL (join (base, "../g"), "http://a/b/g");
  test.ASSERT_EQUAL (join (base, "../.."), "http://a/");
  test.ASSERT_EQUAL (join (base, "../../"), "http://a/");
  test.ASSERT_EQUAL (join (base, "../../g"), "http://a/g");

  // join - abnormal examples - RFC 3986 - section 5.4.2
  test.ASSERT_EQUAL (join (base, "../../../g"), "http://a/g");
  test.ASSERT_EQUAL (join (base, "../../../../g"), "http://a/g");

  test.ASSERT_EQUAL (join (base, "/./g"), "http://a/g");
  test.ASSERT_EQUAL (join (base, "/../g"), "http://a/g");
  test.ASSERT_EQUAL (join (base, "g."), "http://a/b/c/g.");
  test.ASSERT_EQUAL (join (base, ".g"), "http://a/b/c/.g");
  test.ASSERT_EQUAL (join (base, "g.."), "http://a/b/c/g..");
  test.ASSERT_EQUAL (join (base, "..g"), "http://a/b/c/..g");

  test.ASSERT_EQUAL (join (base, "./../g"), "http://a/b/g");
  test.ASSERT_EQUAL (join (base, "./g/."), "http://a/b/c/g/");
  test.ASSERT_EQUAL (join (base, "g/./h"), "http://a/b/c/g/h");
  test.ASSERT_EQUAL (join (base, "g/../h"), "http://a/b/c/h");
  test.ASSERT_EQUAL (join (base, "g;x=1/./y"), "http://a/b/c/g;x=1/y");
  test.ASSERT_EQUAL (join (base, "g;x=1/../y"), "http://a/b/c/y");

  test.ASSERT_EQUAL (join (base, "g?y/./x"), "http://a/b/c/g?y/./x");
  test.ASSERT_EQUAL (join (base, "g?y/../x"), "http://a/b/c/g?y/../x");
  test.ASSERT_EQUAL (join (base, "g#s/./x"), "http://a/b/c/g#s/./x");
  test.ASSERT_EQUAL (join (base, "g#s/../x"), "http://a/b/c/g#s/../x");

  // normalization
  mobius::uri uri12 ("HTTP://WWW.%65xample.COM/src/lib/../doc/index.html");
  uri12.normalize ();

  test.ASSERT_EQUAL (uri12.get_scheme (), "http");
  test.ASSERT_EQUAL (uri12.get_authority (), "www.example.com");
  test.ASSERT_EQUAL (uri12.get_path (), "/src/doc/index.html");
  test.ASSERT_EQUAL (uri12.get_value (), "http://www.example.com/src/doc/index.html");

  // is same document
  mobius::uri uri13 ("HTTP://www.%65xample.com/src/lib/../doc/index.html#chapter1");
  mobius::uri uri14 ("HTTP://www.%65xample.com/src/lib/../doc/index.html#appendixa");

  test.ASSERT_NOT_EQUAL (uri13, uri14);
  test.ASSERT_TRUE (mobius::is_same_document (uri13, uri14));

  test.end ();
}

void
unittest_uri ()
{
  testcase_uri ();
}
