#include "./test_group.hpp"

namespace c4 {
namespace yml {

TEST(single_quoted, test_suite_KSS4)
{
    csubstr yaml = R"(
---
'quoted
string'
--- 'quoted
string'
---
- 'quoted
  string'
---
- 'quoted
string'
---
'quoted
  string': 'quoted
  string'
---
'quoted
string': 'quoted
string'
)";
    test_check_emit_check(yaml, [](Tree const &t){
        EXPECT_EQ(t.docref(0).val(), "quoted string");
        EXPECT_EQ(t.docref(1).val(), "quoted string");
        EXPECT_EQ(t.docref(2)[0].val(), "quoted string");
        EXPECT_EQ(t.docref(3)[0].val(), "quoted string");
        EXPECT_EQ(t.docref(4)["quoted string"].val(), "quoted string");
        EXPECT_EQ(t.docref(5)["quoted string"].val(), "quoted string");
    });
}


TEST(single_quoted, test_suite_R4YG)
{
    csubstr yaml = R"(
- '	

detected

'

)";
    test_check_emit_check(yaml, [](Tree const &t){
        EXPECT_EQ(t[0].val(), csubstr("\t\ndetected\n"));
    });
}


TEST(single_quoted, test_suite_PRH3)
{
    csubstr yaml = R"(
- ' 1st non-empty

 2nd non-empty 
	3rd non-empty '
- ' 1st non-empty

 2nd non-empty 	
 	3rd non-empty '
- ' 1st non-empty

 2nd non-empty	 
	3rd non-empty '
)";
    test_check_emit_check(yaml, [](Tree const &t){
        EXPECT_EQ(t[0].val(), csubstr(" 1st non-empty\n2nd non-empty 3rd non-empty "));
        EXPECT_EQ(t[1].val(), csubstr(" 1st non-empty\n2nd non-empty 3rd non-empty "));
        EXPECT_EQ(t[2].val(), csubstr(" 1st non-empty\n2nd non-empty 3rd non-empty "));
    });
}


TEST(single_quoted, test_suite_T4YY)
{
    csubstr yaml = R"(
---
' 1st non-empty

 2nd non-empty 
 3rd non-empty '
---
'	

detected

'

)";
    test_check_emit_check(yaml, [](Tree const &t){
        ASSERT_TRUE(t.rootref().is_stream());
        ASSERT_TRUE(t.rootref().first_child().is_doc());
        EXPECT_EQ(t.rootref().first_child().val(), csubstr(" 1st non-empty\n2nd non-empty 3rd non-empty "));
    });
}

TEST(single_quoted, test_suite_G4RS)
{
    csubstr yaml = R"(
single: '"Howdy!" he cried.'
quoted: ' # Not a ''comment''.'
tie-fighter: '|\-*-/|'
)";
    test_check_emit_check(yaml, [](Tree const &t){
        EXPECT_EQ(t["single"].val()     , csubstr(R"("Howdy!" he cried.)"));
        EXPECT_EQ(t["quoted"].val()     , csubstr(R"( # Not a 'comment'.)"));
        EXPECT_EQ(t["tie-fighter"].val(), csubstr(R"(|\-*-/|)"));
    });
}

TEST(single_quoted, quotes_are_preserved)
{
    csubstr yaml = R"(
'%ROOT': '%VAL'
'%ROOT2':
  - '%VAL'
  - '%VAL'
)";
    test_check_emit_check(yaml, [](Tree const &t){
        ASSERT_TRUE(t.rootref().is_map());
        ASSERT_TRUE(t.rootref().has_child("%ROOT"));
        ASSERT_TRUE(t.rootref().has_child("%ROOT2"));
        ASSERT_EQ(t["%ROOT2"].num_children(), 2u);
        EXPECT_TRUE(t["%ROOT"].is_key_quoted());
        EXPECT_TRUE(t["%ROOT"].is_val_quoted());
        EXPECT_TRUE(t["%ROOT2"].is_key_quoted());
        EXPECT_TRUE(t["%ROOT2"][0].is_val_quoted());
        EXPECT_TRUE(t["%ROOT2"][1].is_val_quoted());
    });
}


//-----------------------------------------------------------------------------

void verify_error_is_reported(csubstr case_name, csubstr yaml, Location loc={})
{
    SCOPED_TRACE(case_name);
    SCOPED_TRACE(yaml);
    Tree tree;
    ExpectError::do_check(&tree, [&](){
        parse_in_arena(yaml, &tree);
    }, loc);
}

TEST(single_quoted, error_on_unmatched_quotes)
{
    verify_error_is_reported("map block", R"(foo: '"
bar: '')");
    verify_error_is_reported("seq block", R"(- '"
- '')");
    verify_error_is_reported("map flow", R"({foo: '", bar: ''})");
    verify_error_is_reported("seq flow", R"(['", ''])");
}

TEST(single_quoted, error_on_unmatched_quotes_with_escapes)
{
    verify_error_is_reported("map block", R"(foo: '''"
bar: '')");
    verify_error_is_reported("seq block", R"(- '''"
- '')");
    verify_error_is_reported("map flow", R"({foo: '''", bar: ''})");
    verify_error_is_reported("seq flow", R"(['''", ''])");
}

TEST(single_quoted, error_on_unmatched_quotes_at_end)
{
    verify_error_is_reported("map block", R"(foo: ''
bar: '")");
    verify_error_is_reported("seq block", R"(- ''
- '")");
    verify_error_is_reported("map flow", R"({foo: '', bar: '"})");
    verify_error_is_reported("seq flow", R"(['', '"])");
}

TEST(single_quoted, error_on_unmatched_quotes_at_end_with_escapes)
{
    verify_error_is_reported("map block", R"(foo: ''
bar: '''")");
    verify_error_is_reported("seq block", R"(- ''
- '''")");
    verify_error_is_reported("map flow", R"({foo: '', bar: '''"})");
    verify_error_is_reported("seq flow", R"(['', '''"])");
}

TEST(single_quoted, error_on_unclosed_quotes)
{
    verify_error_is_reported("map block", R"(foo: ',
bar: what)");
    verify_error_is_reported("seq block", R"(- '
- what)");
    verify_error_is_reported("map flow", R"({foo: ', bar: what})");
    verify_error_is_reported("seq flow", R"([', what])");
}

TEST(single_quoted, error_on_unclosed_quotes_with_escapes)
{
    verify_error_is_reported("map block", R"(foo: ''',
bar: what)");
    verify_error_is_reported("seq block", R"(- '''
- what)");
    verify_error_is_reported("map flow", R"({foo: ''', bar: what})");
    verify_error_is_reported("seq flow", R"([''', what])");
}

TEST(single_quoted, error_on_unclosed_quotes_at_end)
{
    verify_error_is_reported("map block", R"(foo: what
bar: ')");
    verify_error_is_reported("seq block", R"(- what
- ')");
    verify_error_is_reported("map flow", R"({foo: what, bar: '})");
    verify_error_is_reported("seq flow", R"([what, '])");
}

TEST(single_quoted, error_on_unclosed_quotes_at_end_with_escapes)
{
    verify_error_is_reported("map block", R"(foo: what
bar: ''')");
    verify_error_is_reported("seq block", R"(- what
- ''')");
    verify_error_is_reported("map flow", R"({foo: what, bar: '''})");
    verify_error_is_reported("seq flow", R"([what, '''])");
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

CASE_GROUP(SINGLE_QUOTED)
{

ADD_CASE_TO_GROUP("squoted, only text",
R"('Some text without any quotes.'
)",
  N(DOCVAL | VALQUO, "Some text without any quotes.")
);

ADD_CASE_TO_GROUP("squoted, with double quotes",
R"('Some "text" "with double quotes"')",
  N(DOCVAL | VALQUO, "Some \"text\" \"with double quotes\"")
);

ADD_CASE_TO_GROUP("squoted, with single quotes",
R"('Some text ''with single quotes''')",
  N(DOCVAL | VALQUO, "Some text 'with single quotes'")
);

ADD_CASE_TO_GROUP("squoted, with single and double quotes",
R"('Some text ''with single quotes'' "and double quotes".')",
  N(DOCVAL | VALQUO, "Some text 'with single quotes' \"and double quotes\".")
);

ADD_CASE_TO_GROUP("squoted, with escapes",
R"('Some text with escapes \n \r \t')",
  N(DOCVAL | VALQUO, "Some text with escapes \\n \\r \\t")
);

ADD_CASE_TO_GROUP("squoted, all",
R"('Several lines of text,
containing ''single quotes'' and "double quotes". Escapes (like \n) don''t do anything.

Newlines can be added by leaving a blank line.
            Leading whitespace on lines is ignored.'
)",
  N(DOCVAL | VALQUO, "Several lines of text, containing 'single quotes' and \"double quotes\". Escapes (like \\n) don't do anything.\nNewlines can be added by leaving a blank line. Leading whitespace on lines is ignored.")
);

ADD_CASE_TO_GROUP("squoted, empty",
R"('')",
  N(DOCVAL | VALQUO, "")
);

ADD_CASE_TO_GROUP("squoted, blank",
R"(
- ''
- ' '
- '  '
- '   '
- '    '
)",
  L{N(QV, ""), N(QV, " "), N(QV, "  "), N(QV, "   "), N(QV, "    ")}
);

ADD_CASE_TO_GROUP("squoted, numbers", // these should not be quoted when emitting
R"(
- -1
- -1.0
- +1.0
- 1e-2
- 1e+2
)",
  L{N("-1"), N("-1.0"), N("+1.0"), N("1e-2"), N("1e+2")}
);

ADD_CASE_TO_GROUP("squoted, trailing space",
R"('a aaaa  ')",
  N(DOCVAL | VALQUO, "a aaaa  ")
);

ADD_CASE_TO_GROUP("squoted, leading space",
R"('  a aaaa')",
  N(DOCVAL | VALQUO, "  a aaaa")
);

ADD_CASE_TO_GROUP("squoted, trailing and leading space",
R"('  012345  ')",
  N(DOCVAL | VALQUO, "  012345  ")
);

ADD_CASE_TO_GROUP("squoted, 1 squote",
R"('''')",
  N(DOCVAL | VALQUO, "'")
);

ADD_CASE_TO_GROUP("squoted, 2 squotes",
R"('''''')",
  N(DOCVAL | VALQUO, "''")
);

ADD_CASE_TO_GROUP("squoted, 3 squotes",
R"('''''''')",
  N(DOCVAL | VALQUO, "'''")
);

ADD_CASE_TO_GROUP("squoted, 4 squotes",
R"('''''''''')",
  N(DOCVAL | VALQUO, "''''")
);

ADD_CASE_TO_GROUP("squoted, 5 squotes",
R"('''''''''''')",
  N(DOCVAL | VALQUO, "'''''")
);

/*
ADD_CASE_TO_GROUP("squoted, example 2",
R"('This is a key

that has multiple lines

': and this is its value
)",
  L{N("This is a key\nthat has multiple lines\n", "and this is its value")}
);
*/
}

} // namespace yml
} // namespace c4
