58760b99ae
When hphpd does a print instruction for a value that is an object, the object is serialized in the proxy (server) and then deserialized in the client. If the client VM does not have the class loaded, then the deserializer creates an instance of __PHP_Incomplete_Class and adds the class name to it as the value of a property called __PHP_Incomplete_Class_Name. This then shows up in the textual output of the print command, which is a bit confusing to say the least. Ironically the printed output is obtained by serializing the object instance. The basic design seems OK to me: The proxy should send the client the raw data and then leave it up to the client to figure out how to format it and what elide. And in this case, if the client is accessed via the API, the caller gets the raw data. So, it does not seem like a great idea to get the proxy to format objects so that the client just has to print the string as received from the client. Instead, this diff changes the object serializer so that when the PrintR option (debug output format) is specified, incomplete class instances are serialized with the class name obtained from the value of the __PHP_Incomplete_Class_Name (if present) and the property itself is elided from the output.
1001 linhas
26 KiB
C++
1001 linhas
26 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010- 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/test_cpp_base.h"
|
|
#include "hphp/runtime/base/base_includes.h"
|
|
#include "hphp/util/logger.h"
|
|
#include "hphp/runtime/base/memory/memory_manager.h"
|
|
#include "hphp/runtime/base/builtin_functions.h"
|
|
#include "hphp/runtime/ext/ext_variable.h"
|
|
#include "hphp/runtime/ext/ext_apc.h"
|
|
#include "hphp/runtime/ext/ext_mysql.h"
|
|
#include "hphp/runtime/ext/ext_curl.h"
|
|
#include "hphp/runtime/base/shared/shared_store_base.h"
|
|
#include "hphp/runtime/base/runtime_option.h"
|
|
#include "hphp/runtime/base/server/ip_block_map.h"
|
|
#include "hphp/test/test_mysql_info.h"
|
|
#include "hphp/system/lib/systemlib.h"
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
TestCppBase::TestCppBase() {
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool TestCppBase::RunTests(const std::string &which) {
|
|
bool ret = true;
|
|
RUN_TEST(TestSmartAllocator);
|
|
RUN_TEST(TestString);
|
|
RUN_TEST(TestArray);
|
|
RUN_TEST(TestObject);
|
|
RUN_TEST(TestVariant);
|
|
RUN_TEST(TestIpBlockMap);
|
|
RUN_TEST(TestEqualAsStr);
|
|
return ret;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// building blocks
|
|
|
|
class Timer {
|
|
public:
|
|
explicit Timer(const char *name = nullptr) {
|
|
if (name) m_name = name;
|
|
gettimeofday(&m_start, 0);
|
|
}
|
|
|
|
int64_t getMicroSeconds() {
|
|
struct timeval end;
|
|
gettimeofday(&end, 0);
|
|
return (end.tv_sec - m_start.tv_sec) * 1000000 +
|
|
(end.tv_usec - m_start.tv_usec);
|
|
}
|
|
|
|
private:
|
|
std::string m_name;
|
|
struct timeval m_start;
|
|
};
|
|
|
|
class SomeClass {
|
|
public:
|
|
SomeClass() : m_data(0) {}
|
|
void sweep() {}
|
|
void dump() { printf("data: %d\n", m_data);}
|
|
int m_data;
|
|
};
|
|
|
|
static StaticString s_TestResource("TestResource");
|
|
|
|
class TestResource : public ResourceData {
|
|
public:
|
|
// overriding ResourceData
|
|
CStrRef o_getClassNameHook() const { return s_TestResource; }
|
|
};
|
|
|
|
typedef SmartAllocator<SomeClass>
|
|
SomeClassAlloc;
|
|
|
|
bool TestCppBase::TestSmartAllocator() {
|
|
int iMax = 1000000;
|
|
int64_t time1, time2;
|
|
{
|
|
static IMPLEMENT_THREAD_LOCAL(SomeClassAlloc, allocator);
|
|
|
|
Timer t;
|
|
for (int i = 0; i < iMax; i++) {
|
|
SomeClass *obj = new (allocator.get()) SomeClass();
|
|
allocator.get()->dealloc(obj);
|
|
}
|
|
time1 = t.getMicroSeconds();
|
|
if (!Test::s_quiet) {
|
|
printf("SmartAlloctor: %" PRId64 " us\n", time1);
|
|
}
|
|
}
|
|
{
|
|
Timer t;
|
|
for (int i = 0; i < iMax; i++) {
|
|
SomeClass *obj = new SomeClass();
|
|
delete obj;
|
|
}
|
|
time2 = t.getMicroSeconds();
|
|
if (!Test::s_quiet) {
|
|
printf("malloc/free: %" PRId64 " us\n", time2);
|
|
}
|
|
}
|
|
return Count(true);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// data types
|
|
|
|
bool TestCppBase::TestString() {
|
|
// constructors
|
|
{
|
|
VS(String(15).c_str(), "15");
|
|
VS(String(-15).c_str(), "-15");
|
|
VS(String(int64_t(12345678912345678LL)).c_str(), "12345678912345678");
|
|
VS(String(int64_t(-12345678912345678LL)).c_str(), "-12345678912345678");
|
|
VS(String(5.603).c_str(), "5.603");
|
|
VS(String("test").c_str(), "test");
|
|
VS(String(String("test")).c_str(), "test");
|
|
}
|
|
|
|
// informational
|
|
{
|
|
VERIFY(String().isNull());
|
|
VERIFY(!String("").isNull());
|
|
VERIFY(String().empty());
|
|
VERIFY(String("").empty());
|
|
VERIFY(!String("test").empty());
|
|
VERIFY(String().size() == 0);
|
|
VERIFY(String().length() == 0);
|
|
VERIFY(String("").size() == 0);
|
|
VERIFY(String("").length() == 0);
|
|
VERIFY(String("test").size() == 4);
|
|
VERIFY(String("test").length() == 4);
|
|
VERIFY(!String("2test").isNumeric());
|
|
VERIFY(!String("2test").isInteger());
|
|
VERIFY(!String("2test").isValidVariableName());
|
|
VERIFY(!String("test").isNumeric());
|
|
VERIFY(!String("test").isInteger());
|
|
VERIFY(String("test").isValidVariableName());
|
|
VERIFY(String("23").isNumeric());
|
|
VERIFY(String("23").isInteger());
|
|
VERIFY(String("23.3").isNumeric());
|
|
VERIFY(!String("23.3").isInteger());
|
|
}
|
|
|
|
// operators
|
|
{
|
|
String s;
|
|
s = "test1"; VS(s.c_str(), "test1");
|
|
s = String("test2"); VS(s.c_str(), "test2");
|
|
s = Variant("test3"); VS(s.c_str(), "test3");
|
|
s = String("a") + "b"; VS(s.c_str(), "ab");
|
|
s = String("c") + String("d"); VS(s.c_str(), "cd");
|
|
s += "efg"; VS(s.c_str(), "cdefg");
|
|
s += String("hij"); VS(s.c_str(), "cdefghij");
|
|
|
|
s = String("\x50\x51") | "\x51\x51"; VS(s.c_str(), "\x51\x51");
|
|
s = String("\x50\x51") & "\x51\x51"; VS(s.c_str(), "\x50\x51");
|
|
s = String("\x50\x51") ^ "\x51\x51"; VS(s.c_str(), "\x01");
|
|
s = "\x50\x51"; s |= "\x51\x51"; VS(s.c_str(), "\x51\x51");
|
|
s = "\x50\x51"; s &= "\x51\x51"; VS(s.c_str(), "\x50\x51");
|
|
s = "\x50\x51"; s ^= "\x51\x51"; VS(s.c_str(), "\x01");
|
|
s = "\x50\x51"; s = ~s; VS(s.c_str(), "\xAF\xAE");
|
|
}
|
|
|
|
// manipulations
|
|
{
|
|
String s = StringUtil::ToLower("Test");
|
|
VS(s.c_str(), "test");
|
|
}
|
|
|
|
// conversions
|
|
{
|
|
VERIFY(!String().toBoolean());
|
|
VERIFY(String("123").toBoolean());
|
|
VERIFY(String("123").toByte() == 123);
|
|
VERIFY(String("32767").toInt16() == 32767);
|
|
VERIFY(String("1234567890").toInt32() == 1234567890);
|
|
VERIFY(String("123456789012345678").toInt64() == 123456789012345678LL);
|
|
VERIFY(String("123.45").toDouble() == 123.45);
|
|
}
|
|
|
|
// offset
|
|
{
|
|
VS(String("test").rvalAt(2).c_str(), "s");
|
|
String s = "test";
|
|
s.lvalAt(2) = "";
|
|
VS(s, String("te\0t", 4, AttachLiteral));
|
|
s.lvalAt(2) = "zz";
|
|
VS(s, "tezt");
|
|
s.lvalAt(5) = "q";
|
|
VS(s, "tezt q");
|
|
|
|
String s2 = s; // test copy-on-write
|
|
s.lvalAt(1) = "3";
|
|
VS(s, "t3zt q");
|
|
VS(s2, "tezt q");
|
|
}
|
|
|
|
return Count(true);
|
|
}
|
|
|
|
static const StaticString s_n0("n0");
|
|
static const StaticString s_n1("n1");
|
|
static const StaticString s_n2("n2");
|
|
static const StaticString s_A("A");
|
|
static const StaticString s_name("name");
|
|
static const StaticString s_1("1");
|
|
|
|
bool TestCppBase::TestArray() {
|
|
// Array::Create(), Array constructors and informational
|
|
{
|
|
Array arr;
|
|
VERIFY(arr.empty()); VERIFY(arr.size() == 0); VERIFY(arr.length() == 0);
|
|
VERIFY(arr.isNull());
|
|
|
|
arr = Array::Create();
|
|
VERIFY(arr.empty()); VERIFY(arr.size() == 0); VERIFY(arr.length() == 0);
|
|
VERIFY(!arr.isNull());
|
|
|
|
arr = Array::Create(0);
|
|
VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1);
|
|
VERIFY(!arr.isNull());
|
|
VERIFY((int)arr[0] == 0);
|
|
VS(arr, Array(ArrayInit(1).set(0).create()));
|
|
|
|
arr = Array::Create("test");
|
|
VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1);
|
|
VERIFY(!arr.isNull());
|
|
VERIFY(arr[0] == "test");
|
|
VS(arr, Array(ArrayInit(1).set("test").create()));
|
|
|
|
Array arrCopy = arr;
|
|
arr = Array::Create(arr);
|
|
VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1);
|
|
VERIFY(!arr.isNull());
|
|
VERIFY(arr[0].toArray().size() == 1);
|
|
VS(arr[0], arrCopy);
|
|
VS(arr, Array(ArrayInit(1).set(arrCopy).create()));
|
|
|
|
arr = Array::Create("name", 1);
|
|
VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1);
|
|
VERIFY(!arr.isNull());
|
|
VERIFY((int)arr[s_name] == 1);
|
|
VS(arr, Array(ArrayInit(1).set(s_name, 1).create()));
|
|
|
|
arr = Array::Create(s_name, "test");
|
|
VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1);
|
|
VERIFY(!arr.isNull());
|
|
VERIFY(arr[s_name] == "test");
|
|
VS(arr, Array(ArrayInit(1).set(s_name, "test").create()));
|
|
|
|
arrCopy = arr;
|
|
arr = Array::Create(s_name, arr);
|
|
VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1);
|
|
VERIFY(!arr.isNull());
|
|
VS(arr[s_name], arrCopy);
|
|
VERIFY(arr[s_name].toArray().size() == 1);
|
|
VS(arr, Array(ArrayInit(1).set(s_name, arrCopy).create()));
|
|
}
|
|
|
|
// iteration
|
|
{
|
|
Array arr = CREATE_MAP2("n1", "v1", "n2", "v2");
|
|
int i = 0;
|
|
for (ArrayIter iter = arr.begin(); iter; ++iter, ++i) {
|
|
if (i == 0) {
|
|
VERIFY(iter.first() == "n1");
|
|
VERIFY(iter.second() == "v1");
|
|
} else {
|
|
VERIFY(iter.first() == "n2");
|
|
VERIFY(iter.second() == "v2");
|
|
}
|
|
}
|
|
VERIFY(i == 2);
|
|
}
|
|
/* TODO: fix this
|
|
{
|
|
Variant arr = CREATE_MAP2("n1", "v1", "n2", "v2");
|
|
arr.escalate();
|
|
for (ArrayIterPtr iter = arr.begin(arr, true); !iter->end(); iter->next()){
|
|
unset(arr.lvalAt(iter->first()));
|
|
}
|
|
VS(arr, Array::Create());
|
|
}
|
|
*/
|
|
|
|
// conversions
|
|
{
|
|
Array arr0;
|
|
VERIFY(arr0.toBoolean() == false);
|
|
VERIFY(arr0.toByte() == 0);
|
|
VERIFY(arr0.toInt16() == 0);
|
|
VERIFY(arr0.toInt32() == 0);
|
|
VERIFY(arr0.toInt64() == 0);
|
|
VERIFY(arr0.toDouble() == 0.0);
|
|
VERIFY(arr0.toString() == "");
|
|
|
|
Array arr1 = Array::Create("test");
|
|
VERIFY(arr1.toBoolean() == true);
|
|
VERIFY(arr1.toByte() == 1);
|
|
VERIFY(arr1.toInt16() == 1);
|
|
VERIFY(arr1.toInt32() == 1);
|
|
VERIFY(arr1.toInt64() == 1);
|
|
VERIFY(arr1.toDouble() == 1.0);
|
|
VERIFY(arr1.toString() == "Array");
|
|
}
|
|
|
|
// offset
|
|
{
|
|
Array arr;
|
|
arr.set(0, "v1");
|
|
arr.set(1, "v2");
|
|
VS(arr, CREATE_VECTOR2("v1", "v2"));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.set(s_n1, "v1");
|
|
arr.set(s_n2, "v2");
|
|
VS(arr, CREATE_MAP2("n1", "v1", "n2", "v2"));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(0) = String("v1");
|
|
arr.lvalAt(1) = String("v2");
|
|
VS(arr, CREATE_VECTOR2("v1", "v2"));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(s_n1) = String("v1");
|
|
arr.lvalAt(s_n2) = String("v2");
|
|
VS(arr, CREATE_MAP2("n1", "v1", "n2", "v2"));
|
|
}
|
|
{
|
|
Array arr;
|
|
Variant name = "name";
|
|
arr.lvalAt(name) = String("value");
|
|
VS(arr, CREATE_MAP1("name", "value"));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(s_A) = 10;
|
|
arr.lvalAt(s_A)++;
|
|
VS(arr[s_A], 11);
|
|
}
|
|
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(1) = 10;
|
|
VS(arr[1], 10);
|
|
VS(arr[1.5], 10);
|
|
VS(arr[Variant(1.5)], 10);
|
|
VS(arr[s_1], 10);
|
|
VS(arr[Variant("1")], 10);
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(Variant(1.5)) = 10;
|
|
VS(arr[1], 10);
|
|
VS(arr[1.5], 10);
|
|
VS(arr[Variant(1.5)], 10);
|
|
VS(arr[s_1], 10);
|
|
VS(arr[Variant("1")], 10);
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(s_1) = 10;
|
|
VS(arr[1], 10);
|
|
VS(arr[1.5], 10);
|
|
VS(arr[Variant(1.5)], 10);
|
|
VS(arr[s_1], 10);
|
|
VS(arr[Variant("1")], 10);
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(Variant("1")) = 10;
|
|
VS(arr[1], 10);
|
|
VS(arr[1.5], 10);
|
|
VS(arr[Variant(1.5)], 10);
|
|
VS(arr[s_1], 10);
|
|
VS(arr[Variant("1")], 10);
|
|
}
|
|
|
|
// membership
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(0) = String("v1");
|
|
arr.lvalAt(1) = String("v2");
|
|
VERIFY(arr.exists(0));
|
|
arr.remove(0);
|
|
VERIFY(!arr.exists(0));
|
|
VS(arr, Array::Create(1, "v2"));
|
|
arr.append("v3");
|
|
VS(arr, CREATE_MAP2(1, "v2", 2, "v3"));
|
|
}
|
|
{
|
|
static const StaticString s_0("0");
|
|
Array arr;
|
|
arr.lvalAt(0) = String("v1");
|
|
VERIFY(arr.exists(0));
|
|
arr.remove(String(s_0));
|
|
VERIFY(!arr.exists(0));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(0) = String("v1");
|
|
VERIFY(arr.exists(0));
|
|
arr.remove(Variant("0"));
|
|
VERIFY(!arr.exists(0));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(0) = String("v1");
|
|
VERIFY(arr.exists(0));
|
|
arr.remove(Variant(Variant("0")));
|
|
VERIFY(!arr.exists(0));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(0) = String("v1");
|
|
VERIFY(arr.exists(0));
|
|
arr.remove(Variant(Variant(0.5)));
|
|
VERIFY(!arr.exists(0));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(Variant()) = 123;
|
|
VERIFY(arr.exists(empty_string));
|
|
arr.remove(Variant());
|
|
VERIFY(!arr.exists(empty_string));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(s_n1) = String("v1");
|
|
arr.lvalAt(s_n2) = String("v2");
|
|
VERIFY(arr.exists(s_n1));
|
|
arr.remove(s_n1);
|
|
VERIFY(!arr.exists(s_n1));
|
|
VS(arr, Array::Create(s_n2, "v2"));
|
|
arr.append("v3");
|
|
VS(arr, CREATE_MAP2("n2", "v2", 0, "v3"));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt() = String("test");
|
|
VS(arr, CREATE_VECTOR1("test"));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(s_name) = String("value");
|
|
VERIFY(arr.exists(s_name));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(1) = String("value");
|
|
VERIFY(arr.exists(1));
|
|
VERIFY(arr.exists(1.5));
|
|
VERIFY(arr.exists(s_1));
|
|
VERIFY(arr.exists(Variant("1")));
|
|
VERIFY(arr.exists(Variant(1)));
|
|
VERIFY(arr.exists(Variant(1.5)));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(s_1) = String("value");
|
|
VERIFY(arr.exists(1));
|
|
VERIFY(arr.exists(1.5));
|
|
VERIFY(arr.exists(s_1));
|
|
VERIFY(arr.exists(Variant("1")));
|
|
VERIFY(arr.exists(Variant(1)));
|
|
VERIFY(arr.exists(Variant(1.5)));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(1.5) = String("value");
|
|
VERIFY(arr.exists(1));
|
|
VERIFY(arr.exists(1.5));
|
|
VERIFY(arr.exists(s_1));
|
|
VERIFY(arr.exists(Variant("1")));
|
|
VERIFY(arr.exists(Variant(1)));
|
|
VERIFY(arr.exists(Variant(1.5)));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(Variant(1.5)) = String("value");
|
|
VERIFY(arr.exists(1));
|
|
VERIFY(arr.exists(1.5));
|
|
VERIFY(arr.exists(s_1));
|
|
VERIFY(arr.exists(Variant("1")));
|
|
VERIFY(arr.exists(Variant(1)));
|
|
VERIFY(arr.exists(Variant(1.5)));
|
|
}
|
|
{
|
|
Array arr;
|
|
arr.lvalAt(Variant("1")) = String("value");
|
|
VERIFY(arr.exists(1));
|
|
VERIFY(arr.exists(1.5));
|
|
VERIFY(arr.exists(s_1));
|
|
VERIFY(arr.exists(Variant("1")));
|
|
VERIFY(arr.exists(Variant(1)));
|
|
VERIFY(arr.exists(Variant(1.5)));
|
|
}
|
|
|
|
// merge
|
|
{
|
|
Array arr = Array::Create(0) + Array::Create(1);
|
|
VS(arr, Array::Create(0));
|
|
arr += CREATE_VECTOR2(0, 1);
|
|
VS(arr, CREATE_VECTOR2(0, 1));
|
|
|
|
arr = Array::Create(0).merge(Array::Create(1));
|
|
VS(arr, CREATE_VECTOR2(0, 1));
|
|
arr = arr.merge(CREATE_VECTOR2(0, 1));
|
|
VS(arr, CREATE_VECTOR4(0, 1, 0, 1));
|
|
|
|
arr = Array::Create("s0").merge(Array::Create("s1"));
|
|
VS(arr, CREATE_VECTOR2("s0", "s1"));
|
|
|
|
arr = Array::Create("n0", "s0") + Array::Create("n1", "s1");
|
|
VS(arr, CREATE_MAP2("n0", "s0", "n1", "s1"));
|
|
arr += CREATE_MAP2("n0", "s0", "n1", "s1");
|
|
VS(arr, CREATE_MAP2("n0", "s0", "n1", "s1"));
|
|
|
|
arr = Array::Create("n0", "s0").merge(Array::Create("n1", "s1"));
|
|
VS(arr, CREATE_MAP2("n0", "s0", "n1", "s1"));
|
|
Array arrX = CREATE_MAP2("n0", "s2", "n1", "s3");
|
|
arr = arr.merge(arrX);
|
|
VS(arr, CREATE_MAP2("n0", "s2", "n1", "s3"));
|
|
}
|
|
|
|
// slice
|
|
{
|
|
Array arr = CREATE_VECTOR2("test1", "test2");
|
|
Array sub = arr.slice(1, 1, true);
|
|
VS(sub, CREATE_MAP1(1, "test2"));
|
|
}
|
|
{
|
|
Array arr = CREATE_VECTOR2("test1", "test2");
|
|
Array sub = arr.slice(1, 1, false);
|
|
VS(sub, CREATE_VECTOR1("test2"));
|
|
}
|
|
{
|
|
Array arr = CREATE_MAP2("n1", "test1", "n2", "test2");
|
|
Array sub = arr.slice(1, 1, true);
|
|
VS(sub, CREATE_MAP1("n2", "test2"));
|
|
}
|
|
{
|
|
Array arr = CREATE_MAP2("n1", "test1", "n2", "test2");
|
|
Array sub = arr.slice(1, 1, false);
|
|
VS(sub, CREATE_MAP1("n2", "test2"));
|
|
}
|
|
|
|
// escalation
|
|
{
|
|
Array arr;
|
|
lval(arr.lvalAt(0)).lvalAt(0) = 1.2;
|
|
VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2)));
|
|
}
|
|
{
|
|
Array arr;
|
|
lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2;
|
|
VS(arr, CREATE_MAP1(s_name, CREATE_VECTOR1(1.2)));
|
|
}
|
|
{
|
|
Array arr = Array::Create();
|
|
lval(arr.lvalAt(0)).lvalAt(0) = 1.2;
|
|
VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2)));
|
|
}
|
|
{
|
|
Array arr = Array::Create();
|
|
lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2;
|
|
VS(arr, CREATE_MAP1(s_name, CREATE_VECTOR1(1.2)));
|
|
}
|
|
{
|
|
Array arr = Array::Create("test");
|
|
arr.lvalAt(0) = CREATE_VECTOR1(1.2);
|
|
VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2)));
|
|
}
|
|
{
|
|
Array arr = Array::Create("test");
|
|
lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2;
|
|
VS(arr, CREATE_MAP2(0, "test", s_name, CREATE_VECTOR1(1.2)));
|
|
}
|
|
{
|
|
Array arr = Array::Create();
|
|
arr.append("apple");
|
|
arr.set(2, "pear");
|
|
VS(arr[2], "pear");
|
|
}
|
|
|
|
{
|
|
Array arr = CREATE_MAP2(0, "a", 1, "b");
|
|
VERIFY(arr->isVectorData());
|
|
}
|
|
{
|
|
Array arr = CREATE_MAP2(1, "a", 0, "b");
|
|
VERIFY(!arr->isVectorData());
|
|
}
|
|
{
|
|
Array arr = CREATE_MAP2(1, "a", 2, "b");
|
|
VERIFY(!arr->isVectorData());
|
|
}
|
|
{
|
|
Array arr = CREATE_MAP1(1, "a");
|
|
arr.set(0, "b");
|
|
VERIFY(!arr->isVectorData());
|
|
}
|
|
|
|
return Count(true);
|
|
}
|
|
|
|
bool TestCppBase::TestObject() {
|
|
{
|
|
String s = "O:1:\"B\":1:{s:3:\"obj\";O:1:\"A\":1:{s:1:\"a\";i:10;}}";
|
|
Variant v = unserialize_from_string(s);
|
|
VERIFY(v.isObject());
|
|
auto o = v.toObject();
|
|
VS(o->o_getClassName(), "__PHP_Incomplete_Class");
|
|
auto os = f_serialize(o);
|
|
VS(os, "O:1:\"B\":1:{s:3:\"obj\";O:1:\"A\":1:{s:1:\"a\";i:10;}}");
|
|
}
|
|
VERIFY(!equal(Object(new TestResource()), Object(new TestResource()) ));
|
|
return Count(true);
|
|
}
|
|
|
|
bool TestCppBase::TestVariant() {
|
|
// operators
|
|
{
|
|
Variant v(15);
|
|
v += 20;
|
|
VERIFY(v.isNumeric());
|
|
VERIFY(v.is(KindOfInt64));
|
|
VERIFY(v == Variant(35));
|
|
}
|
|
|
|
// conversions
|
|
{
|
|
Variant v("123");
|
|
VERIFY(v.toInt32() == 123);
|
|
}
|
|
|
|
// offset
|
|
{
|
|
Variant v = "test";
|
|
VS(v.rvalAt(0), "t");
|
|
}
|
|
{
|
|
Variant v;
|
|
v.lvalAt(0) = String("v0");
|
|
v.lvalAt(1) = String("v1");
|
|
VERIFY(v[0] == "v0");
|
|
VERIFY(v[1] == "v1");
|
|
}
|
|
{
|
|
Variant v;
|
|
v.lvalAt() = String("test");
|
|
VS(v, CREATE_VECTOR1("test"));
|
|
}
|
|
{
|
|
Variant v;
|
|
v.lvalAt(1) = String("test");
|
|
VS(v[1], "test");
|
|
VS(v[1.5], "test");
|
|
VS(v[Variant(1.5)], "test");
|
|
VS(v[s_1], "test");
|
|
VS(v[Variant("1")], "test");
|
|
}
|
|
{
|
|
Variant v;
|
|
v.lvalAt(Variant(1.5)) = String("test");
|
|
VS(v[1], "test");
|
|
VS(v[1.5], "test");
|
|
VS(v[Variant(1.5)], "test");
|
|
VS(v[s_1], "test");
|
|
VS(v[Variant("1")], "test");
|
|
}
|
|
{
|
|
Variant v;
|
|
v.lvalAt(s_1) = String("test");
|
|
VS(v[1], "test");
|
|
VS(v[1.5], "test");
|
|
VS(v[Variant(1.5)], "test");
|
|
VS(v[s_1], "test");
|
|
VS(v[Variant("1")], "test");
|
|
}
|
|
{
|
|
Variant v;
|
|
v.lvalAt(Variant("1")) = String("test");
|
|
VS(v[1], "test");
|
|
VS(v[1.5], "test");
|
|
VS(v[Variant(1.5)], "test");
|
|
VS(v[s_1], "test");
|
|
VS(v[Variant("1")], "test");
|
|
}
|
|
|
|
// membership
|
|
{
|
|
Variant v;
|
|
v.lvalAt(s_n0) = String("v0");
|
|
v.lvalAt(s_n1) = String("v1");
|
|
v.remove(s_n1);
|
|
VS(v, CREATE_MAP1(s_n0, "v0"));
|
|
v.append("v2");
|
|
VS(v, CREATE_MAP2(s_n0, "v0", 0, "v2"));
|
|
}
|
|
{
|
|
Variant v;
|
|
v.lvalAt(s_n0) = String("v0");
|
|
v.lvalAt(1) = String("v1");
|
|
v.remove(Variant(1.5));
|
|
VS(v, CREATE_MAP1("n0", "v0"));
|
|
}
|
|
{
|
|
Variant v;
|
|
v.lvalAt(s_n0) = String("v0");
|
|
v.lvalAt(1) = String("v1");
|
|
v.remove(Variant("1"));
|
|
VS(v, CREATE_MAP1("n0", "v0"));
|
|
}
|
|
{
|
|
Variant v;
|
|
v.lvalAt(s_n0) = String("v0");
|
|
v.lvalAt(1) = String("v1");
|
|
v.remove(String("1"));
|
|
VS(v, CREATE_MAP1("n0", "v0"));
|
|
}
|
|
{
|
|
Variant v;
|
|
v.lvalAt(s_n0) = String("v0");
|
|
v.lvalAt(empty_string) = String("v1");
|
|
v.remove(Variant());
|
|
VS(v, CREATE_MAP1("n0", "v0"));
|
|
}
|
|
|
|
// references
|
|
{
|
|
Variant v1("original");
|
|
Variant v2 = v1;
|
|
v2 = String("changed");
|
|
VERIFY(v1 == "original");
|
|
}
|
|
{
|
|
Variant v1("original");
|
|
Variant v2 = strongBind(v1);
|
|
v2 = String("changed");
|
|
VERIFY(v1 == "changed");
|
|
}
|
|
{
|
|
Variant v1 = 10;
|
|
Variant v2 = Array(ArrayInit(1).setRef(v1).create());
|
|
v1 = 20;
|
|
VS(v2[0], 20);
|
|
}
|
|
{
|
|
Variant v1 = 10;
|
|
Variant v2;
|
|
v2.lvalAt() = ref(v1);
|
|
v1 = 20;
|
|
VS(v2[0], 20);
|
|
}
|
|
{
|
|
Variant v1 = 10;
|
|
Variant v2 = CREATE_VECTOR1(5);
|
|
v2.lvalAt() = ref(v1);
|
|
v1 = 20;
|
|
VS(v2[1], 20);
|
|
}
|
|
{
|
|
Variant v1 = 10;
|
|
Variant v2 = strongBind(v1);
|
|
v2++;
|
|
VS(v2, 11);
|
|
VS(v1, 11);
|
|
}
|
|
{
|
|
Variant arr = CREATE_VECTOR2(1, 2);
|
|
Variant v;
|
|
for (MutableArrayIter iter = arr.begin(nullptr, v); iter.advance();) {
|
|
v++;
|
|
}
|
|
VS(arr, CREATE_VECTOR2(2, 3));
|
|
}
|
|
|
|
// array escalation
|
|
{
|
|
Variant arr;
|
|
lval(arr.lvalAt(0)).lvalAt(0) = 1.2;
|
|
VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2)));
|
|
}
|
|
{
|
|
Variant arr;
|
|
lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2;
|
|
VS(arr, CREATE_MAP1(s_name, CREATE_VECTOR1(1.2)));
|
|
}
|
|
{
|
|
Variant arr = Array::Create();
|
|
lval(arr.lvalAt(0)).lvalAt(0) = 1.2;
|
|
VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2)));
|
|
}
|
|
{
|
|
Variant arr = Array::Create();
|
|
lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2;
|
|
VS(arr, CREATE_MAP1(s_name, CREATE_VECTOR1(1.2)));
|
|
}
|
|
{
|
|
Variant arr = Array::Create("test");
|
|
arr.lvalAt(0) = CREATE_VECTOR1(1.2);
|
|
VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2)));
|
|
}
|
|
{
|
|
Variant arr = Array::Create("test");
|
|
lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2;
|
|
VS(arr, CREATE_MAP2(0, "test", s_name, CREATE_VECTOR1(1.2)));
|
|
}
|
|
|
|
return Count(true);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class TestGlobals {
|
|
public:
|
|
TestGlobals() {
|
|
String a = "apple";
|
|
m_string = a + "orange"; // so mallocing m_data internally
|
|
|
|
m_array = CREATE_MAP2("a", "apple", "b", "orange");
|
|
}
|
|
|
|
Variant m_string;
|
|
Array m_array;
|
|
Variant m_string2;
|
|
Array m_array2;
|
|
Variant m_conn;
|
|
Variant m_curlconn;
|
|
Variant m_curlMultiConn;
|
|
String key;
|
|
String value;
|
|
DECLARE_SMART_ALLOCATION(TestGlobals);
|
|
void dump() {}
|
|
};
|
|
IMPLEMENT_SMART_ALLOCATION(TestGlobals);
|
|
|
|
/* Pull 32bit Big Endian words from an in6_addr */
|
|
static inline long in6addrWord(struct in6_addr addr, char wordNo) {
|
|
return ((addr.s6_addr[(wordNo*4)+0] << 24) |
|
|
(addr.s6_addr[(wordNo*4)+1] << 16) |
|
|
(addr.s6_addr[(wordNo*4)+2] << 8) |
|
|
(addr.s6_addr[(wordNo*4)+3] << 0)) & 0xFFFFFFFF;
|
|
}
|
|
|
|
bool TestCppBase::TestIpBlockMap() {
|
|
struct in6_addr addr;
|
|
int bits;
|
|
|
|
VERIFY(IpBlockMap::ReadIPv6Address("204.15.21.0/22", &addr, bits));
|
|
VS(bits, 118);
|
|
VS(in6addrWord(addr, 0), 0x00000000L);
|
|
VS(in6addrWord(addr, 1), 0x00000000L);
|
|
VS(in6addrWord(addr, 2), 0x0000FFFFL);
|
|
VS(in6addrWord(addr, 3), 0xCC0F1500L);
|
|
|
|
VERIFY(IpBlockMap::ReadIPv6Address("127.0.0.1", &addr, bits));
|
|
VS(bits, 128);
|
|
VS(in6addrWord(addr, 0), 0x00000000L);
|
|
VS(in6addrWord(addr, 1), 0x00000000L);
|
|
VS(in6addrWord(addr, 2), 0x0000FFFFL);
|
|
VS(in6addrWord(addr, 3), 0x7F000001L);
|
|
|
|
VERIFY(IpBlockMap::ReadIPv6Address(
|
|
"1111:2222:3333:4444:5555:6666:789a:bcde", &addr, bits));
|
|
VS(bits, 128);
|
|
VS(in6addrWord(addr, 0), 0x11112222L);
|
|
VS(in6addrWord(addr, 1), 0x33334444L);
|
|
VS(in6addrWord(addr, 2), 0x55556666L);
|
|
VS(in6addrWord(addr, 3), 0x789abcdeL);
|
|
|
|
VERIFY(IpBlockMap::ReadIPv6Address(
|
|
"1111:2222:3333:4444:5555:6666:789a:bcde/68", &addr, bits));
|
|
VS(bits, 68);
|
|
VS(in6addrWord(addr, 0), 0x11112222L);
|
|
VS(in6addrWord(addr, 1), 0x33334444L);
|
|
VS(in6addrWord(addr, 2), 0x55556666L);
|
|
VS(in6addrWord(addr, 3), 0x789abcdeL);
|
|
|
|
IpBlockMap::BinaryPrefixTrie root(true);
|
|
unsigned char value[16];
|
|
|
|
// Default value with no additional nodes
|
|
memset(value, 0, 16);
|
|
VERIFY(root.isAllowed(value, 1));
|
|
value[0] = 0x80;
|
|
VERIFY(root.isAllowed(value));
|
|
|
|
// Inheritance of parent allow value through multiple levels of new nodes
|
|
IpBlockMap::BinaryPrefixTrie::InsertNewPrefix(&root, value, 1, false);
|
|
value[0] = 0xf0;
|
|
IpBlockMap::BinaryPrefixTrie::InsertNewPrefix(&root, value, 4, true);
|
|
VERIFY(root.isAllowed(value));
|
|
value[0] = 0xe0;
|
|
VERIFY(!root.isAllowed(value));
|
|
value[0] = 0xc0;
|
|
VERIFY(!root.isAllowed(value));
|
|
value[0] = 0x80;
|
|
VERIFY(!root.isAllowed(value));
|
|
value[0] = 0;
|
|
VERIFY(root.isAllowed(value));
|
|
|
|
// > 1 byte in address
|
|
value[2] = 0xff;
|
|
IpBlockMap::BinaryPrefixTrie::InsertNewPrefix(&root, value, 24, false);
|
|
VERIFY(!root.isAllowed(value));
|
|
value[3] = 0xff;
|
|
VERIFY(!root.isAllowed(value));
|
|
value[2] = 0xfe;
|
|
VERIFY(root.isAllowed(value));
|
|
|
|
// Exact address match
|
|
value[2] = 0xff;
|
|
value[15] = 1;
|
|
IpBlockMap::BinaryPrefixTrie::InsertNewPrefix(&root, value, 128, true);
|
|
VERIFY(root.isAllowed(value));
|
|
|
|
Hdf hdf;
|
|
hdf.fromString(
|
|
" 0 {\n"
|
|
" Location = /test\n"
|
|
" AllowFirst = true\n"
|
|
" Ip {\n"
|
|
" Allow {\n"
|
|
" * = 127.0.0.1\n"
|
|
" }\n"
|
|
" Deny {\n"
|
|
" * = 8.32.0.0/24\n"
|
|
" * = aaaa:bbbb:cccc:dddd:eeee:ffff:1111::/80\n"
|
|
" }\n"
|
|
" }\n"
|
|
" }\n"
|
|
);
|
|
|
|
IpBlockMap ibm(hdf);
|
|
VERIFY(!ibm.isBlocking("test/blah.php", "127.0.0.1"));
|
|
VERIFY(ibm.isBlocking("test/blah.php", "8.32.0.104"));
|
|
VERIFY(ibm.isBlocking("test/blah.php",
|
|
"aaaa:bbbb:cccc:dddd:eeee:9999:8888:7777"));
|
|
VERIFY(!ibm.isBlocking("test/blah.php",
|
|
"aaaa:bbbb:cccc:dddd:eee3:4444:3333:2222"));
|
|
|
|
return Count(true);
|
|
}
|
|
|
|
bool TestCppBase::TestEqualAsStr() {
|
|
|
|
const int arr_len = 18;
|
|
Variant var_array[arr_len];
|
|
var_array[0] = false;
|
|
var_array[1] = true;
|
|
var_array[2] = 0;
|
|
var_array[3] = 1;
|
|
var_array[4] = 42;
|
|
var_array[5] = 0.0;
|
|
var_array[6] = 1.0;
|
|
var_array[7] = 42.2;
|
|
var_array[8] = String("0");
|
|
var_array[9] = String("1");
|
|
var_array[10] = String("42");
|
|
var_array[11] = String("x");
|
|
var_array[12] = Array::Create();
|
|
Variant v1("original");
|
|
var_array[13] = v1;
|
|
Variant v2("changed");
|
|
var_array[14] = v2;
|
|
var_array[15] = empty_string;
|
|
var_array[16] = String("Array");
|
|
var_array[17] = String("ARRAY");
|
|
for (int i = 0; i < arr_len; i++) {
|
|
for (int j = 0; j < arr_len; j++) {
|
|
bool eqAsStr = equalAsStr(var_array[i], var_array[j]);
|
|
bool sm = same(toString(var_array[i]), toString(var_array[j]));
|
|
VERIFY(eqAsStr == sm);
|
|
}
|
|
}
|
|
return Count(true);
|
|
}
|