/* +----------------------------------------------------------------------+ | 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/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 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"); } // 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); }