Arquivos
hhvm/hphp/test/ext/test_cpp_base.cpp
T
Drew Paroski 84b9d9a3a2 Separate resources from objects, part 1
In HHVM (and HPHPc before it) we've been piggybacking resources on the
KindOfObject machinery. At the language level, resource is considered to
be a different type than object, and there are a number of differences
in behavior between objects and resources (ex. resources don't allow for
dynamic properties, resources don't work with the clone operator, the
"(object)" cast behaves differently for resources vs. objects, etc).

Piggybacking resources on the KindOfObject machinery has some downsides.
Code that deals with KindOfObject values often needs to check if the value
is a resource and go down a different code path. This makes things harder
to maintain and harder to keep parity with Zend. Also, these extra branches
hurt performance a little, and they make it harder for the JIT to do a good
job in some cases when its generating machine code that operates on objects.

This diff prepares the code base for a new KindOfResource type by adding a
new "Resource" smart pointer type (currently a typedef for the Object smart
pointer type) and it updates the C++ code and the idl files appropriately.
This diff is essentially a cosmetic change and should not impact run time
behavior. In the next diff (part 2) we'll actually add a new KindOfResource
type, detach ResourceData from the ObjectData inheritence hierarchy, and
provide a real implementation for the Resource smart pointer type (instead
of just aliasing the Object smart pointer type).
2013-07-10 11:16:33 -07:00

935 linhas
24 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_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/ext/test_mysql_info.h"
#include "hphp/system/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);
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.set(2, String(""));
VS(s, String("te\0t", 4, AttachLiteral));
s.set(2, String("zz"));
VS(s, "tezt");
s.set(5, String("q"));
VS(s, "tezt q");
String s2 = s; // test copy-on-write
s.set(1, String("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(arr[0].toInt32() == 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(equal(arr[0], String("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(arr[s_name].toInt32() == 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(equal(arr[s_name], String("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(equal(iter.first(), String("n1")));
VERIFY(equal(iter.second(), String("v1")));
} else {
VERIFY(equal(iter.first(), String("n2")));
VERIFY(equal(iter.second(), String("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[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[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[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[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(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(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(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(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;
arr.lvalAt(0).lvalAt(0) = 1.2;
VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2)));
}
{
Array arr;
arr.lvalAt(s_name).lvalAt(0) = 1.2;
VS(arr, CREATE_MAP1(s_name, CREATE_VECTOR1(1.2)));
}
{
Array arr = Array::Create();
arr.lvalAt(0).lvalAt(0) = 1.2;
VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2)));
}
{
Array arr = Array::Create();
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");
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(Resource(new TestResource()), Resource(new TestResource()) ));
return Count(true);
}
bool TestCppBase::TestVariant() {
// 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(equal(v[0], String("v0")));
VERIFY(equal(v[1], String("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[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[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[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[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(equal(v1, String("original")));
}
{
Variant v1("original");
Variant v2 = strongBind(v1);
v2 = String("changed");
VERIFY(equal(v1, String("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;
arr.lvalAt(0).lvalAt(0) = 1.2;
VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2)));
}
{
Variant arr;
arr.lvalAt(s_name).lvalAt(0) = 1.2;
VS(arr, CREATE_MAP1(s_name, CREATE_VECTOR1(1.2)));
}
{
Variant arr = Array::Create();
arr.lvalAt(0).lvalAt(0) = 1.2;
VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2)));
}
{
Variant arr = Array::Create();
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");
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);
}