Arquivos
hhvm/hphp/test/ext/test_ext_fb.cpp
T
Paul Tarjan e433cd193c move compiled tests files into another dir
I've been linking people to the README in this directory, but it is hard to see with all these files in here. What do people think about it moving a subdirectory? I don't love the name.
2013-06-06 11:39:06 -07:00

375 linhas
12 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/test/ext/test_ext_fb.h"
#include "hphp/runtime/ext/ext_fb.h"
#include "hphp/runtime/base/runtime_option.h"
#include "hphp/runtime/ext/ext_iconv.h"
///////////////////////////////////////////////////////////////////////////////
bool TestExtFb::RunTests(const std::string &which) {
bool ret = true;
DECLARE_TEST_FUNCTIONS("function test($s1) {"
" return $s1;"
"}");
RUN_TEST(test_fb_compact_serialize);
RUN_TEST(test_fb_compact_unserialize);
RUN_TEST(test_fb_thrift_serialize);
RUN_TEST(test_fb_thrift_unserialize);
RUN_TEST(test_fb_rename_function);
RUN_TEST(test_fb_utf8ize);
RUN_TEST(test_fb_utf8_strlen);
RUN_TEST(test_fb_utf8_strlen_deprecated);
RUN_TEST(test_fb_utf8_substr);
RUN_TEST(test_fb_call_user_func_safe);
RUN_TEST(test_fb_call_user_func_safe_return);
RUN_TEST(test_fb_call_user_func_array_safe);
RUN_TEST(test_fb_load_local_databases);
RUN_TEST(test_fb_parallel_query);
RUN_TEST(test_fb_crossall_query);
return ret;
}
///////////////////////////////////////////////////////////////////////////////
#define fb_cs_test(v) do { \
Variant ret; \
Variant v_ = v; \
Variant s_ = f_fb_compact_serialize(v_); \
VERIFY(s_.isString()); \
String ss_ = s_.toString(); \
VERIFY(!ss_.empty()); \
/* check high bit of first character always set */ \
VERIFY(ss_[0] & 0x80); \
VS(f_fb_compact_unserialize(s_, ref(ret)), v_); \
VERIFY(same(ret, true)); \
ret = uninit_null(); \
VS(f_fb_unserialize(s_, ref(ret)), v_); \
VERIFY(same(ret, true)); \
} while(0)
bool TestExtFb::test_fb_compact_serialize() {
fb_cs_test(uninit_null());
fb_cs_test(true);
fb_cs_test(false);
fb_cs_test(1234.5678);
fb_cs_test("");
fb_cs_test("a");
fb_cs_test("\0");
fb_cs_test("\0 a");
fb_cs_test("0123012301230123");
fb_cs_test("0123012301230123a");
fb_cs_test("012301230123012");
fb_cs_test(Array());
fb_cs_test(CREATE_VECTOR1(12345));
fb_cs_test(CREATE_VECTOR3(12345,"abc",0.1234));
fb_cs_test(CREATE_MAP1(1, 12345));
fb_cs_test(CREATE_MAP3(1, 12345, "a", 123124, "sdf", 0.1234));
fb_cs_test(CREATE_VECTOR1(CREATE_VECTOR1("a")));
fb_cs_test(CREATE_VECTOR2(1, CREATE_VECTOR1("a")));
fb_cs_test(CREATE_VECTOR2(CREATE_VECTOR1("a"), 1));
fb_cs_test(CREATE_VECTOR2(CREATE_VECTOR1("a"), CREATE_VECTOR1(1)));
// Test skips
fb_cs_test(CREATE_MAP3(0, "a", 1, "b", 3, "c"));
fb_cs_test(CREATE_MAP3(1, "a", 2, "b", 3, "c"));
fb_cs_test(CREATE_MAP3(0, "a", 2, "b", 3, "c"));
fb_cs_test(CREATE_MAP1(3, "a"));
// Test for overflow
fb_cs_test(CREATE_MAP1((int64_t)((1ULL << 63) - 1), "a"));
// Test each power of two, +/- 1 and the negatives of them
// Test a single number and packed inside an array
for (int i = 0; i < 64; ++i) {
int64_t n = (1ULL << i);
fb_cs_test(n); fb_cs_test(CREATE_VECTOR1(n));
fb_cs_test(n-1); fb_cs_test(CREATE_VECTOR1(n-1));
fb_cs_test(n+1); fb_cs_test(CREATE_VECTOR1(n+1));
fb_cs_test(-n); fb_cs_test(CREATE_VECTOR1(-n));
fb_cs_test(-n-1); fb_cs_test(CREATE_VECTOR1(-n-1));
fb_cs_test(-n+1); fb_cs_test(CREATE_VECTOR1(-n+1));
}
// Test vector code (PHP can't create those, but they might come form
// C++ code in serialized strings)
String s("\xfe\x01\x02\x03\xfc"); // VECTOR, 1, 2, 3, STOP
Variant ret;
VS(f_fb_compact_unserialize(s, ref(ret)), CREATE_VECTOR3(1, 2, 3));
return Count(true);
}
#undef fb_cs_test
bool TestExtFb::test_fb_compact_unserialize() {
// tested above
return Count(true);
}
///////////////////////////////////////////////////////////////////////////////
bool TestExtFb::test_fb_thrift_serialize() {
Variant ret;
VS(f_fb_thrift_unserialize(f_fb_thrift_serialize("test"), ref(ret)), "test");
VERIFY(same(ret, true));
ret = uninit_null();
VS(f_fb_thrift_unserialize(f_fb_thrift_serialize(CREATE_VECTOR1("test")),
ref(ret)),
CREATE_VECTOR1("test"));
VERIFY(same(ret, true));
return Count(true);
}
bool TestExtFb::test_fb_thrift_unserialize() {
// tested above
return Count(true);
}
bool TestExtFb::test_fb_rename_function() {
// tested in TestCodeRun
return Count(true);
}
// This string includes an invalid UTF-8 sequence. The first byte
// suggests this is a three-byte UTF-8 sequence, but it's not valid.
//
// The legacy fb_utf8ize() implementation used to treat this three-byte
// sequence as two invalid code points followed by a valid ASCII character.
// It transforms the three bytes to the three code point sequence
// \xef\xbf\xbd\xef\xbf\xbd\x28.
//
// ICU treats this three-byte sequence as one invalid two-byte code point
// followed by a valid ASCII character. An ICU-based fb_utf8ize()
// implementation will transform the three bytes to the two code point
// sequence \xef\xbf\xbd\x28.
static const char *INVALID_UTF_8_STRING = "\xe2\x82\x28";
bool TestExtFb::test_fb_utf8ize() {
for (int i = 0; i < 2; i++) {
RuntimeOption::Utf8izeReplace = (i == 0);
{
Variant s = "hon\xE7k";
VERIFY(f_fb_utf8ize(ref(s)));
if (RuntimeOption::Utf8izeReplace) {
VS(s, "hon\uFFFDk");
} else {
VS(s, "honk");
}
}
{
Variant s = "test\xE0\xB0\xB1\xE0";
VERIFY(f_fb_utf8ize(ref(s)));
if (RuntimeOption::Utf8izeReplace) {
VS(s, "test\xE0\xB0\xB1\uFFFD");
} else {
VS(s, "test\xE0\xB0\xB1");
}
}
{
Variant s = "test\xE0\xB0\xB1\xE0\xE0";
VERIFY(f_fb_utf8ize(ref(s)));
if (RuntimeOption::Utf8izeReplace) {
VS(s, "test\xE0\xB0\xB1\uFFFD\uFFFD");
} else {
VS(s, "test\xE0\xB0\xB1");
}
}
{
Variant s = "\xfc";
VERIFY(f_fb_utf8ize(ref(s)));
if (RuntimeOption::Utf8izeReplace) {
VS(s, "\uFFFD");
} else {
VS(s, "");
}
}
{
Variant s = "\xfc\xfc";
VERIFY(f_fb_utf8ize(ref(s)));
if (RuntimeOption::Utf8izeReplace) {
VS(s, "\uFFFD\uFFFD");
} else {
VS(s, "");
}
}
{
// We intentionally consider null bytes invalid sequences.
Variant s = String("abc\0def", 7, AttachLiteral);
VERIFY(f_fb_utf8ize(ref(s)));
if (RuntimeOption::Utf8izeReplace) {
VS(s, "abc\uFFFD""def");
} else {
VS(s, "abcdef");
}
}
{
// ICU treats this as as two code points.
// The old implementation treated this as three code points.
Variant s = INVALID_UTF_8_STRING;
VERIFY(f_fb_utf8ize(ref(s)));
if (RuntimeOption::Utf8izeReplace) {
VS(s, "\uFFFD""\x28");
} else {
VS(s, "\x28");
}
}
}
return Count(true);
}
// fb_utf8_strlen_deprecated() returns byte count on invalid input.
bool TestExtFb::test_fb_utf8_strlen_deprecated() {
// Invalid UTF-8 sequence fails.
VS(f_fb_utf8_strlen_deprecated(INVALID_UTF_8_STRING), 3);
return Count(true);
}
bool TestExtFb::test_fb_utf8_strlen() {
VS(f_fb_utf8_strlen(""), 0);
VS(f_fb_utf8_strlen("a"), 1);
VS(f_fb_utf8_strlen("ab"), 2);
// Valid UTF-8 sequence returns code point count.
VS(f_fb_utf8_strlen("\ub098\ub294"), 2);
VS(f_fb_utf8_strlen(INVALID_UTF_8_STRING), 2);
for (int i = 0; i < 2; i++) {
// Test utf8ize() handling of invalid UTF-8 sequences and how
// fb_utf8_strlen() counts them.
// RuntimeOption::Utf8izeReplace set to non-zero value replaces invalid
// bytes, including '\0' with a special UTF-8 code point: "\uFFFD".
// RuntimeOption::Utf8izeReplace set to zero deletes the invalid
// byte then continues parsing.
RuntimeOption::Utf8izeReplace = (i == 0);
{
Variant s = String("abc\0def", 7, AttachLiteral);
VS(s.toString().size(), 7);
VS(f_fb_utf8_strlen(s), 7);
f_fb_utf8ize(ref(s)); // Modifies s
int ret = s.toString().size();
if (RuntimeOption::Utf8izeReplace) {
VS(ret, 9); // '\0' converted to "\uFFFD"
} else {
VS(ret, 6); // '\0' deleted from s
}
ret = f_fb_utf8_strlen(s);
if (RuntimeOption::Utf8izeReplace) {
VS(ret, 7); // '\0' and "\uFFFD" are both one code point, so no change
} else {
VS(ret, 6); // '\0' deleted, so one fewer code point
}
}
}
return Count(true);
}
bool TestExtFb::test_fb_utf8_substr() {
// Falsey inputs
VS(f_fb_utf8_substr("", 0, 0), false);
VS(f_fb_utf8_substr("", 0, 1), false);
VS(f_fb_utf8_substr("hon\xE7k", 0, INT_MAX), "hon\uFFFDk");
VS(f_fb_utf8_substr("hon\xE7k", 0, 3), "hon"); // Never hits invalid byte
VS(f_fb_utf8_substr("hon\xE7k", -4, INT_MAX), "on\uFFFDk");
// Common cases
VS(f_fb_utf8_substr("X", 0, 1), "X");
VS(f_fb_utf8_substr("Hello", 0, INT_MAX), "Hello");
VS(f_fb_utf8_substr("Hello", 1, 2), "el");
VS(f_fb_utf8_substr("Pr\u00DC\u00DDx", 2, 2), "\u00DC\u00DD");
// Negative start
VS(f_fb_utf8_substr("abcdef", -1, INT_MAX), "f");
VS(f_fb_utf8_substr("abcdef", -2, INT_MAX), "ef");
VS(f_fb_utf8_substr("abcdef", -3, 1), "d");
VS(f_fb_utf8_substr("", -1, 1), false);
VS(f_fb_utf8_substr("X", -1, 1), "X");
VS(f_fb_utf8_substr("XY", -1, 1), "Y");
VS(f_fb_utf8_substr("Pr\u00DC\u00DDx", -3, 2), "\u00DC\u00DD");
// Negative lengths
VS(f_fb_utf8_substr("abcdef", 0, -1), "abcde");
VS(f_fb_utf8_substr("abcdef", 2, -1), "cde");
VS(f_fb_utf8_substr("abcdef", 4, -4), false); // nothing to return
VS(f_fb_utf8_substr("abcdef", -3, -1), "de");
// Invalid sequence
VS(f_fb_utf8_substr(INVALID_UTF_8_STRING, 0), "\uFFFD\x28");
return Count(true);
}
bool TestExtFb::test_fb_call_user_func_safe() {
{
Variant ret = f_fb_call_user_func_safe
(1, "TEst", CREATE_VECTOR1("param"));
VS(ret, CREATE_VECTOR2(true, "param"));
}
{
Variant ret = f_fb_call_user_func_safe
(1, "NonTEst", CREATE_VECTOR1("param"));
VS(ret, CREATE_VECTOR2(false, uninit_null()));
}
return Count(true);
}
bool TestExtFb::test_fb_call_user_func_safe_return() {
{
Variant ret = f_fb_call_user_func_safe_return
(1, "TEst", "ok", CREATE_VECTOR1("param"));
VS(ret, "param");
}
{
Variant ret = f_fb_call_user_func_safe_return
(1, "NonTEst", "ok", CREATE_VECTOR1("param"));
VS(ret, "ok");
}
return Count(true);
}
bool TestExtFb::test_fb_call_user_func_array_safe() {
{
Variant ret = f_fb_call_user_func_array_safe
("TEst", CREATE_VECTOR1("param"));
VS(ret, CREATE_VECTOR2(true, "param"));
}
{
Variant ret = f_fb_call_user_func_array_safe
("NonTest", CREATE_VECTOR1("param"));
VS(ret, CREATE_VECTOR2(false, uninit_null()));
}
return Count(true);
}
bool TestExtFb::test_fb_load_local_databases() {
// tested with PHP unit tests
return Count(true);
}
bool TestExtFb::test_fb_parallel_query() {
// tested with PHP unit tests
return Count(true);
}
bool TestExtFb::test_fb_crossall_query() {
// tested with PHP unit tests
return Count(true);
}