/* vim: set ts=8 sts=4 sw=4 tw=80 noet: */
/*======================================================================
Copyright (C) 2004,2005,2009 Walter Doekes <walter+tthsum@wjd.nu>
This file is part of tthsum.

tthsum 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 3 of the License, or
(at your option) any later version.

tthsum 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 tthsum.  If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#include "escape.h"

#include "test.h"
#include "texts.h"
#include <string.h>


static int help_cmp_symmetric(const char* str, const char* escaped,
	int should_fail) {
    char strbuf[2048];
    char escapedbuf[2048];

    if (strlen(str) >= 512 || strlen(escaped) >= 2048)
	FAIL3("Test values too large: \"%s\" is %u and %u bytes", escaped,
		(unsigned)strlen(str), (unsigned)strlen(escaped));
    strtoctrlesc(escapedbuf, str);
    if (ctrlesctostr(strbuf, escaped) != 0)
	FAIL2("ctrlesctostr failed on \"%s\": %s", escaped, get_error());
    if ((strcmp(strbuf, str) != 0 || strcmp(escapedbuf, escaped) != 0)
	    == !should_fail)
	FAIL2("Values %sdiffer for \"%s\"", should_fail ? "do NOT " : "",
		escaped);

    return 0;
}

static int help_cmp_unescape(const char* escaped, const char* result,
	    int should_fail) {
    char resultbuf[2048];

    if (strlen(escaped) >= 2048)
	FAIL2("Test value too large: \"%s\" is %u bytes", escaped,
		(unsigned)strlen(escaped));
    if (ctrlesctostr(resultbuf, escaped) != 0)
	FAIL2("ctrlesctostr failed on \"%s\": %s", escaped, get_error());
    if (strcmp(resultbuf, result) == !should_fail)
	FAIL2("Values %sdiffer for \"%s\"", should_fail ? "do NOT " : "",
		escaped);

    return 0;
}

static int test_bidirectional_success() {
    return help_cmp_symmetric("", "", 0)
	    + help_cmp_symmetric("ABC", "ABC", 0)
	    + help_cmp_symmetric("\xff ABC \x80\x81", "\xff ABC \x80\x81", 0)
	    + help_cmp_symmetric(
		"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
		"\\x01\\x02\\x03\\x04\\x05\\x06\\a\\b\\t\\n\\v\\f\\r\\x0e\\x0f",
		0)
	    + help_cmp_symmetric(
		"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e"
		"\x1f", "\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19"
		"\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f", 0);
}

static int test_bidirectional_fail() {
    return help_cmp_symmetric(" ", "", 1)
	 + help_cmp_symmetric("ABC", "ABCD", 1)
	 + help_cmp_symmetric("\n", "\\x0a", 1)
	 + help_cmp_symmetric("\r\n", "\\n\\n", 1)
	 + help_cmp_symmetric("\0", "\\x00", 1); /* \0 is not seen */
}

static int test_unidirectional_success() {
    return help_cmp_unescape("\\x0d\\n", "\r\n", 0)
	 + help_cmp_unescape("abcdef", "abcdef", 0)
	 + help_cmp_unescape("abc\\x0a\\x0d\\t", "abc\n\r\t", 0)
	 + help_cmp_unescape("\\x00foobar", "", 0) /* leading \0 */
	 + help_cmp_unescape("\\\\x80\x81\\xff", "\\x80\x81\xff", 0);
}

static int test_unidirectional_fail() {
    return help_cmp_unescape("\\x0d\\n", "\\x0d\n", 1)
	 + help_cmp_unescape("abcdef", "abcdefg", 1)
	 + help_cmp_unescape("abc\\x0a\\x0d\\t", "abc\\n\\r\\t", 1)
	 + help_cmp_unescape("\\x00foobar", "foobar", 1)
	 + help_cmp_unescape("\\\\x80\x81\\xff", "\x80\x81\xff", 1);
}

static int test_decode_success() {
    char buf[256];
    return ctrlesctostr(buf, "\\x11")
	|| ctrlesctostr(buf, "abc\\x00def")
	|| ctrlesctostr(buf, "\\x0a\\n\\r\\x0d")
	|| ctrlesctostr(buf, "\a\b\t\v\r\n")
	|| ctrlesctostr(buf, "\\x1A\\x1a");
}

static int test_decode_fail() {
    char buf[256];
    return !ctrlesctostr(buf, "\\x1")
	|| !ctrlesctostr(buf, "\\0")
	|| !ctrlesctostr(buf, "\\0\\1\\2")
	|| !ctrlesctostr(buf, "\\x1g")
	|| !ctrlesctostr(buf, "\\g")
	|| !ctrlesctostr(buf, "\\N")
	|| !ctrlesctostr(buf, "\\x1G");
}


TESTS(escape_test)
    TEST(test_bidirectional_success);
    TEST(test_bidirectional_fail);
    TEST(test_unidirectional_success);
    TEST(test_unidirectional_fail);
    TEST(test_decode_success);
    TEST(test_decode_fail);
ENDTESTS
