Files
c3c/test/unit/stdlib/net/url_encoding.c3
2025-02-18 18:53:30 +01:00

142 lines
3.4 KiB
Plaintext

module url_encode_test @test;
import std::io;
import std::net::url @public;
struct EncodeTest
{
String in;
String out;
anyfault err;
UrlEncodingMode mode;
}
EncodeTest[?] decode_with_error_tests @local = {
{ "", "", {}, QUERY, },
{ "abc", "abc", {}, QUERY, },
{ "1%41", "1A", {}, QUERY, },
{ "1%41%42%43", "1ABC", {}, QUERY, },
{ "%4a", "J", {}, QUERY, },
{ "%6F", "o", {}, QUERY, },
{ "%", "", UrlDecodingError.INVALID_HEX, QUERY, },
{ "%a", "", UrlDecodingError.INVALID_HEX, QUERY, },
{ "%1", "", UrlDecodingError.INVALID_HEX, QUERY, },
{ "123%45%6", "", UrlDecodingError.INVALID_HEX, QUERY, },
{ "%zzzzz", "", UrlDecodingError.INVALID_HEX, QUERY, },
{ "a+b", "a b", {}, QUERY, },
{ "a%20b", "a b", {}, QUERY, },
};
fn void test_decoding_with_error() => @pool()
{
foreach (test: decode_with_error_tests)
{
String! actual = url::temp_decode(test.in, test.mode);
if (catch excuse = actual)
{
assert(excuse == test.err, "unescape(%s, %s); "
"got: %s, want: %s", test.in, test.mode, excuse, test.err);
continue;
}
assert(actual == test.out, "unescape(%s, %s); "
"got: %s, want: %s", test.in, test.mode, actual, test.out);
}
}
EncodeTest[?] encode_tests @local = {
{ "", "", {}, PATH, },
{ "abc", "abc", {}, PATH, },
{ "abc+def", "abc+def", {}, PATH, },
{ "a/b", "a/b", {}, PATH, },
{ "one two", "one%20two", {}, PATH, },
{ "10%", "10%25", {}, PATH, },
{ "", "", {}, QUERY, },
{ "abc", "abc", {}, QUERY, },
{ "one two", "one+two", {}, QUERY, },
{ "10%", "10%25", {}, QUERY, },
{ " ?&=#+%!<>#\"{}|\\^[]`☺\t:/@$'()*,;",
"+%3F%26%3D%23%2B%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09%3A%2F%40%24%27%28%29%2A%2C%3B",
{}, QUERY,
},
};
fn void test_percent_encode_and_decode() => @pool()
{
foreach (test: encode_tests)
{
String actual = url::temp_encode(test.in, test.mode);
assert(actual == test.out, "escape(%s, %s); "
"got: %s, want: %s", test.in, test.mode, actual, test.out);
actual = url::temp_decode(test.out, test.mode)!!;
assert(actual == test.in, "unescape(%s, %s); "
"got: %s, want: %s", test.out, test.mode, actual, test.in);
}
}
struct ShouldEncodeTest
{
char in;
UrlEncodingMode mode;
bool escape;
}
ShouldEncodeTest[?] should_encode_tests = {
{'a', PATH, false},
{'a', USERPASS, false},
{'a', QUERY, false},
{'a', FRAGMENT, false},
{'a', HOST, false},
{'z', PATH, false},
{'A', PATH, false},
{'Z', PATH, false},
{'0', PATH, false},
{'9', PATH, false},
{'-', PATH, false},
{'-', USERPASS, false},
{'-', QUERY, false},
{'-', FRAGMENT, false},
{'.', PATH, false},
{'_', PATH, false},
{'~', PATH, false},
{'/', USERPASS, true},
{'?', USERPASS, true},
{'@', USERPASS, true},
{'$', USERPASS, false},
{'&', USERPASS, false},
{'+', USERPASS, false},
{',', USERPASS, false},
{';', USERPASS, false},
{'=', USERPASS, false},
{'!', HOST, false},
{'$', HOST, false},
{'&', HOST, false},
{'\'',HOST, false},
{'(', HOST, false},
{')', HOST, false},
{'*', HOST, false},
{'+', HOST, false},
{',', HOST, false},
{';', HOST, false},
{'=', HOST, false},
{'0', HOST, false},
{'9', HOST, false},
{'A', HOST, false},
{'z', HOST, false},
{'_', HOST, false},
{'-', HOST, false},
{'.', HOST, false},
};
fn void test_should_encode()
{
foreach (test : should_encode_tests)
{
bool actual = url::should_encode(test.in, test.mode);
assert(actual == test.escape, "should_encode(%c, %s); "
"got: %s, want: %s", test.in, test.mode, actual, test.escape);
}
}