//
//  test-UriParser.c
//  snowcrash
//
//  Created by Carl Griffiths on 24/02/14.
//  Copyright (c) 2014 Apiary Inc. All rights reserved.
//

#include <catch2/catch.hpp>
#include "UriTemplateParser.h"

using namespace snowcrash;

TEST_CASE("Parse a valid uri into separate parts", "[validuriparser][issue][79]")
{

    const snowcrash::URI uri = "http://www.test.com/other/{id}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);
    REQUIRE(result.scheme == "http");
    REQUIRE(result.host == "www.test.com");
    REQUIRE(result.path == "/other/{id}");
    REQUIRE(result.report.warnings.size() == 0);
}

TEST_CASE("Parse an invalid uri into separate parts", "[invaliduriparser][issue][79]")
{

    const snowcrash::URI uri = "http://www.test.com/other/{id}[2]";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);
    REQUIRE(result.scheme == "http");
    REQUIRE(result.host == "www.test.com");
    REQUIRE(result.path == "/other/{id}[2]");
    REQUIRE(result.report.warnings.size() == 1);
}

TEST_CASE("Parse uri template for invalid format curly brackets (nested brackets)",
    "[invalidcurlybracketparsingnested][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/{id{}}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 2);
    CHECK(result.report.warnings[0].message == "URI template variable 'id{' contains invalid nested expression brace '{', which should be encoded as '%7B'. Allowed characters for expressions are A-Z a-z 0-9 _ and percent encoded characters");
    CHECK(result.report.warnings[1].message == "URI template contains disallowed character '}'. Disallowed characters must be percent encoded.");
}

TEST_CASE("Parse uri template for invalid format curly brackets (missing end bracket)",
    "[invalidcurlybracketparsingmissingendbracket][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/{id";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 1);
    CHECK(result.report.warnings[0].message == "URI Template expression is missing closing bracket '}'");
}

TEST_CASE("Parse uri template for supported level one variable expansion",
    "[supportedlevelonevariableexpansionexpression][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/{id}/{test}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 0);
}

TEST_CASE("Parse uri template for supported variables with % encoding and explode modifier",
    "[supportedpercentencodedvariablesandexplodemodifier][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/{id}/{?test%20one,test%20two*}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 0);
}

TEST_CASE("Parse uri template for invalid % encoding", "[invalidpercentencoding][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/{id}/{?test%20one,test%2Ztwo}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 1);
}

TEST_CASE("Parse uri template for invalid expansion", "[invalidexpression][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/{@id}/{|test}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 2);
}

TEST_CASE("Parse uri template for supported level two fragment expansion",
    "[supportedleveltwofragmentexpansionexpression][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/path{id}{#var}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 0);
}

TEST_CASE("Parse uri template for supported level three form style query string expansion",
    "[supportedlevelthreeformstylequeryexpansionexpression][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/path{?varone,vartwo}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 0);
}

TEST_CASE("Parse uri template for supported level three reserved expansion",
    "[supportedlevelthreeformstylequeryexpansionexpression][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/path{+varone}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 0);
}

TEST_CASE("Parse uri template for unsupported level three label expansion",
    "[unsupportedlevelthreelabelexpansionexpression][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/path{.varone}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 1);
}

TEST_CASE("Parse uri template for unsupported level three path segment expansion",
    "[unsupportedlevelthreepathsegmentexpansionexpression][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/path{/varone}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 1);
}

TEST_CASE("Parse uri template for unsupported level three path style parameter expansion",
    "[unsupportedlevelthreepathstyleparameterexpression][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/path{;varone,vartwo}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 1);
}

TEST_CASE("Parse uri template for supported level three form style query continuation expansion",
    "[supportedlevelthreeformstylequerycontinuationexpression][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/{id}?path=test{&varone,vartwo}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 0);
}

TEST_CASE(
    "Parse uri template for invalid variable name, contains spaces", "[invalidvariablenamecontainingspaces][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/path{?varone, vartwo}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 1);
    REQUIRE(result.report.warnings[0].message == "URI template variable ' vartwo' contains invalid character ' ', which should be encoded as '%20'. Allowed characters for expressions are A-Z a-z 0-9 _ and percent encoded characters");
}

TEST_CASE("Parse uri template for invalid variable name, contains hyphens",
    "[invalidvariablenamecontainingshyphens][issue][78]")
{
    const snowcrash::URI uri = "http://www.test.com/{id}{?var-one,var-two}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 2);
    REQUIRE(result.report.warnings[0].message == "URI template variable 'var-one' contains invalid character '-', which should be encoded as '%2D'. Allowed characters for expressions are A-Z a-z 0-9 _ and percent encoded characters");
    REQUIRE(result.report.warnings[1].message == "URI template variable 'var-two' contains invalid character '-', which should be encoded as '%2D'. Allowed characters for expressions are A-Z a-z 0-9 _ and percent encoded characters");
}

TEST_CASE("Parse uri template for invalid variable name, contains assignment",
    "[invalidvariablenamecontainingsassignment][issue][78]")
{
    const snowcrash::URITemplate uri = "http://www.test.com/{id}{?varone=vartwo}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 1);
    REQUIRE(result.report.warnings[0].message == "URI template variable 'varone=vartwo' contains invalid character '=', which should be encoded as '%3D'. Allowed characters for expressions are A-Z a-z 0-9 _ and percent encoded characters");
}

TEST_CASE("Parse uri template for invalid variable name, invalid % encoded",
    "[invalidvariablenamecontainingsbadpctencoding][issue][78]")
{
    const snowcrash::URITemplate uri = "http://www.test.com/{id}{?varone%2z}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 1);
    REQUIRE(result.report.warnings[0].message == "URI template variable 'varone%2z' contains invalid percent encoded character '%2z'. Allowed characters for expressions are A-Z a-z 0-9 _ and percent encoded characters");
}

TEST_CASE("Parse uri template for invalid variable name, invalid % encoded with one char",
    "[invalidvariablenamecontainingsbadpctencoding]")
{
    const snowcrash::URITemplate uri = "http://www.test.com/{id}{?varone%2}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 1);
    REQUIRE(result.report.warnings[0].message == "URI template variable 'varone%2' contains invalid character '%', which should be encoded as '%25'. Allowed characters for expressions are A-Z a-z 0-9 _ and percent encoded characters");
}

TEST_CASE("Parse uri template for variable name containing dot", "[validvariablenamecontainingdot][issue][78]")
{
    const snowcrash::URITemplate uri = "http://www.test.com/{id}{?varone.data}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 0);
}

TEST_CASE("Parse uri template for invalid variable name containing multiple contiguous dots",
    "[invalidvariablenamecontiguousdots][issue][78]")
{
    const snowcrash::URITemplate uri = "http://www.test.com/{id}{?varone..data}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 1);
    REQUIRE(result.report.warnings[0].message == "URI template variable 'varone..data' contains invalid continuous dots '..'. Allowed characters for expressions are A-Z a-z 0-9 _ and percent encoded characters");
}

TEST_CASE("Parse uri template for consistent invalid character warning",
    "[invalidexpressionconsistentinvalidcharacterwarning][issue][78]")
{
    const snowcrash::URITemplate urione = "http://www.test.com/{$a,b,c}";

    URITemplateParser parser;
    ParsedURITemplate result;
    ParsedURITemplate result2;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(urione, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 1);
    REQUIRE(result.report.warnings[0].message == "URI template variable '$a' contains invalid character '$', which should be encoded as '%24'. Allowed characters for expressions are A-Z a-z 0-9 _ and percent encoded characters");

}

TEST_CASE("Parse uri template for variable name containing multibyte utf-8 char")
{
    const snowcrash::URITemplate uri = "http://www.test.com/{var荒data}";

    URITemplateParser parser;
    ParsedURITemplate result;
    mdp::CharactersRangeSet sourceBlock;

    parser.parse(uri, sourceBlock, result);

    REQUIRE(result.report.warnings.size() == 1);
    REQUIRE(result.report.warnings[0].message == "URI template variable 'var荒data' contains invalid character '荒', which should be encoded as '%E8%8D%92'. Allowed characters for expressions are A-Z a-z 0-9 _ and percent encoded characters");
}
