diff options
Diffstat (limited to 'webkit/glue/cpp_variant_unittest.cc')
-rw-r--r-- | webkit/glue/cpp_variant_unittest.cc | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/webkit/glue/cpp_variant_unittest.cc b/webkit/glue/cpp_variant_unittest.cc new file mode 100644 index 0000000..43c78de --- /dev/null +++ b/webkit/glue/cpp_variant_unittest.cc @@ -0,0 +1,426 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/compiler_specific.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" +#include "webkit/glue/cpp_variant.h" + +using WebKit::WebBindings; + +// Creates a std::string from an NPVariant of string type. If the NPVariant +// is not a string, empties the std::string. +void MakeStdString(const NPVariant& np, std::string* std_string) { + if (np.type == NPVariantType_String) { + const char* chars = + reinterpret_cast<const char*>(np.value.stringValue.UTF8Characters); + (*std_string).assign(chars, np.value.stringValue.UTF8Length); + } else { + (*std_string).clear(); + } +} + +// Verifies that the actual NPVariant is a string and that its value matches +// the expected_str. +void CheckString(const std::string& expected_str, const NPVariant& actual) { + EXPECT_EQ(NPVariantType_String, actual.type); + std::string actual_str; + MakeStdString(actual, &actual_str); + EXPECT_EQ(expected_str, actual_str); +} + +// Verifies that both the actual and the expected NPVariants are strings and +// that their values match. +void CheckString(const NPVariant& expected, const NPVariant& actual) { + EXPECT_EQ(NPVariantType_String, expected.type); + std::string expected_str; + MakeStdString(expected, &expected_str); + CheckString(expected_str, actual); +} + +int g_allocate_call_count = 0; +int g_deallocate_call_count = 0; + +void CheckObject(const NPVariant& actual) { + EXPECT_EQ(NPVariantType_Object, actual.type); + EXPECT_TRUE(actual.value.objectValue); + EXPECT_EQ(1U, actual.value.objectValue->referenceCount); + EXPECT_EQ(1, g_allocate_call_count); + EXPECT_EQ(0, g_deallocate_call_count); +} + +NPObject* MockNPAllocate(NPP npp, NPClass* aClass) { + // This is a mock allocate method that mimics the behavior + // of WebBindings::createObject when allocate() is NULL + + ++g_allocate_call_count; + // Ignore npp and NPClass + return reinterpret_cast<NPObject*>(malloc(sizeof(NPObject))); +} + +void MockNPDeallocate(NPObject* npobj) { + // This is a mock deallocate method that mimics the behavior + // of NPN_DeallocateObject when deallocate() is NULL + + ++g_deallocate_call_count; + free(npobj); +} + +static NPClass void_class = { NP_CLASS_STRUCT_VERSION, + MockNPAllocate, + MockNPDeallocate, + 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +NPObject* MakeVoidObject() { + g_allocate_call_count = 0; + g_deallocate_call_count = 0; + return WebBindings::createObject(NULL, &void_class); +} + +TEST(CppVariantTest, NewVariantHasNullType) { + CppVariant value; + EXPECT_EQ(NPVariantType_Null, value.type); +} + +TEST(CppVariantTest, SetNullSetsType) { + CppVariant value; + value.Set(17); + value.SetNull(); + EXPECT_EQ(NPVariantType_Null, value.type); +} + +TEST(CppVariantTest, CopyConstructorDoesDeepCopy) { + CppVariant source; + source.Set("test string"); + CppVariant dest = source; + EXPECT_EQ(NPVariantType_String, dest.type); + EXPECT_EQ(NPVariantType_String, source.type); + + // Ensure that the string was copied, not just the pointer. + EXPECT_NE(source.value.stringValue.UTF8Characters, + dest.value.stringValue.UTF8Characters); + + CheckString(source, dest); +} + +TEST(CppVariantTest, CopyConstructorIncrementsRefCount) { + CppVariant source; + NPObject *object = MakeVoidObject(); + source.Set(object); + // 2 references so far. + EXPECT_EQ(2U, source.value.objectValue->referenceCount); + + CppVariant dest = source; + EXPECT_EQ(3U, dest.value.objectValue->referenceCount); + EXPECT_EQ(1, g_allocate_call_count); + WebBindings::releaseObject(object); + source.SetNull(); + CheckObject(dest); +} + +TEST(CppVariantTest, AssignmentDoesDeepCopy) { + CppVariant source; + source.Set("test string"); + CppVariant dest; + dest = source; + EXPECT_EQ(NPVariantType_String, dest.type); + EXPECT_EQ(NPVariantType_String, source.type); + + // Ensure that the string was copied, not just the pointer. + EXPECT_NE(source.value.stringValue.UTF8Characters, + dest.value.stringValue.UTF8Characters); + + CheckString(source, dest); +} + +TEST(CppVariantTest, AssignmentIncrementsRefCount) { + CppVariant source; + NPObject *object = MakeVoidObject(); + source.Set(object); + // 2 references so far. + EXPECT_EQ(2U, source.value.objectValue->referenceCount); + + CppVariant dest; + dest = source; + EXPECT_EQ(3U, dest.value.objectValue->referenceCount); + EXPECT_EQ(1, g_allocate_call_count); + + WebBindings::releaseObject(object); + source.SetNull(); + CheckObject(dest); +} + +TEST(CppVariantTest, DestroyingCopyDoesNotCorruptSource) { + CppVariant source; + source.Set("test string"); + std::string before; + MakeStdString(source, &before); + { + CppVariant dest = source; + } + CheckString(before, source); + + NPObject *object = MakeVoidObject(); + source.Set(object); + { + CppVariant dest2 = source; + } + WebBindings::releaseObject(object); + CheckObject(source); +} + +TEST(CppVariantTest, CopiesTypeAndValueToNPVariant) { + NPVariant np; + CppVariant cpp; + + cpp.Set(true); + cpp.CopyToNPVariant(&np); + EXPECT_EQ(cpp.type, np.type); + EXPECT_EQ(cpp.value.boolValue, np.value.boolValue); + WebBindings::releaseVariantValue(&np); + + cpp.Set(17); + cpp.CopyToNPVariant(&np); + EXPECT_EQ(cpp.type, np.type); + EXPECT_EQ(cpp.value.intValue, np.value.intValue); + WebBindings::releaseVariantValue(&np); + + cpp.Set(3.1415); + cpp.CopyToNPVariant(&np); + EXPECT_EQ(cpp.type, np.type); + EXPECT_EQ(cpp.value.doubleValue, np.value.doubleValue); + WebBindings::releaseVariantValue(&np); + + cpp.Set("test value"); + cpp.CopyToNPVariant(&np); + CheckString("test value", np); + WebBindings::releaseVariantValue(&np); + + cpp.SetNull(); + cpp.CopyToNPVariant(&np); + EXPECT_EQ(cpp.type, np.type); + WebBindings::releaseVariantValue(&np); + + NPObject *object = MakeVoidObject(); + cpp.Set(object); + cpp.CopyToNPVariant(&np); + WebBindings::releaseObject(object); + cpp.SetNull(); + CheckObject(np); + WebBindings::releaseVariantValue(&np); +} + +TEST(CppVariantTest, SetsTypeAndValueFromNPVariant) { + NPVariant np; + CppVariant cpp; + + VOID_TO_NPVARIANT(np); + cpp.Set(np); + EXPECT_EQ(np.type, cpp.type); + WebBindings::releaseVariantValue(&np); + + NULL_TO_NPVARIANT(np); + cpp.Set(np); + EXPECT_EQ(np.type, cpp.type); + WebBindings::releaseVariantValue(&np); + + BOOLEAN_TO_NPVARIANT(true, np); + cpp.Set(np); + EXPECT_EQ(np.type, cpp.type); + EXPECT_EQ(np.value.boolValue, cpp.value.boolValue); + WebBindings::releaseVariantValue(&np); + + INT32_TO_NPVARIANT(15, np); + cpp.Set(np); + EXPECT_EQ(np.type, cpp.type); + EXPECT_EQ(np.value.intValue, cpp.value.intValue); + WebBindings::releaseVariantValue(&np); + + DOUBLE_TO_NPVARIANT(2.71828, np); + cpp.Set(np); + EXPECT_EQ(np.type, cpp.type); + EXPECT_EQ(np.value.doubleValue, cpp.value.doubleValue); + WebBindings::releaseVariantValue(&np); + + NPString np_ascii_str = { "1st test value", + static_cast<uint32_t>(strlen("1st test value")) }; + WebBindings::initializeVariantWithStringCopy(&np, &np_ascii_str); + cpp.Set(np); + CheckString("1st test value", cpp); + WebBindings::releaseVariantValue(&np); + + // Test characters represented in 2/3/4 bytes in UTF-8 + // Greek alpha, Chinese number 1 (horizontal bar), + // Deseret letter (similar to 'O') + NPString np_intl_str = { "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84", + static_cast<uint32_t>(strlen( + "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84")) }; + WebBindings::initializeVariantWithStringCopy(&np, &np_intl_str); + cpp.Set(np); + CheckString("\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84", cpp); + WebBindings::releaseVariantValue(&np); + + NPObject *obj = MakeVoidObject(); + OBJECT_TO_NPVARIANT(obj, np); // Doesn't make a copy. + cpp.Set(np); + // Use this or WebBindings::releaseObject but NOT both. + WebBindings::releaseVariantValue(&np); + CheckObject(cpp); +} + +TEST(CppVariantTest, SetsSimpleTypesAndValues) { + CppVariant cpp; + cpp.Set(true); + EXPECT_EQ(NPVariantType_Bool, cpp.type); + EXPECT_EQ(true, cpp.value.boolValue); + + cpp.Set(5); + EXPECT_EQ(NPVariantType_Int32, cpp.type); + EXPECT_EQ(5, cpp.value.intValue); + + cpp.Set(1.234); + EXPECT_EQ(NPVariantType_Double, cpp.type); + EXPECT_EQ(1.234, cpp.value.doubleValue); + + // C string + cpp.Set("1st test string"); + CheckString("1st test string", cpp); + + // std::string + std::string source("std test string"); + cpp.Set(source); + CheckString("std test string", cpp); + + // NPString + NPString np_ascii_str = { "test NPString", + static_cast<uint32_t>(strlen("test NPString")) }; + cpp.Set(np_ascii_str); + std::string expected("test NPString"); + CheckString(expected, cpp); + + // Test characters represented in 2/3/4 bytes in UTF-8 + // Greek alpha, Chinese number 1 (horizontal bar), + // Deseret letter (similar to 'O') + NPString np_intl_str = { "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84", + static_cast<uint32_t>(strlen( + "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84")) }; + cpp.Set(np_intl_str); + expected = std::string("\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84"); + CheckString(expected, cpp); + + NPObject* obj = MakeVoidObject(); + cpp.Set(obj); + WebBindings::releaseObject(obj); + CheckObject(cpp); +} + +TEST(CppVariantTest, FreeDataSetsToVoid) { + CppVariant cpp; + EXPECT_EQ(NPVariantType_Null, cpp.type); + cpp.Set(12); + EXPECT_EQ(NPVariantType_Int32, cpp.type); + cpp.FreeData(); + EXPECT_EQ(NPVariantType_Void, cpp.type); +} + +TEST(CppVariantTest, FreeDataReleasesObject) { + CppVariant cpp; + NPObject* object = MakeVoidObject(); + cpp.Set(object); + EXPECT_EQ(2U, object->referenceCount); + cpp.FreeData(); + EXPECT_EQ(1U, object->referenceCount); + EXPECT_EQ(0, g_deallocate_call_count); + + cpp.Set(object); + WebBindings::releaseObject(object); + EXPECT_EQ(0, g_deallocate_call_count); + cpp.FreeData(); + EXPECT_EQ(1, g_deallocate_call_count); +} + +TEST(CppVariantTest, IsTypeFunctionsWork) { + CppVariant cpp; + // These should not happen in practice, since voids are not supported + // This test must be first since it just clobbers internal data without + // releasing. + VOID_TO_NPVARIANT(cpp); + EXPECT_FALSE(cpp.isBool()); + EXPECT_FALSE(cpp.isInt32()); + EXPECT_FALSE(cpp.isDouble()); + EXPECT_FALSE(cpp.isNumber()); + EXPECT_FALSE(cpp.isString()); + EXPECT_TRUE(cpp.isVoid()); + EXPECT_FALSE(cpp.isNull()); + EXPECT_TRUE(cpp.isEmpty()); + + cpp.Set(true); + EXPECT_TRUE(cpp.isBool()); + EXPECT_FALSE(cpp.isInt32()); + EXPECT_FALSE(cpp.isDouble()); + EXPECT_FALSE(cpp.isNumber()); + EXPECT_FALSE(cpp.isString()); + EXPECT_FALSE(cpp.isVoid()); + EXPECT_FALSE(cpp.isNull()); + EXPECT_FALSE(cpp.isEmpty()); + EXPECT_FALSE(cpp.isObject()); + + cpp.Set(12); + EXPECT_FALSE(cpp.isBool()); + EXPECT_TRUE(cpp.isInt32()); + EXPECT_FALSE(cpp.isDouble()); + EXPECT_TRUE(cpp.isNumber()); + EXPECT_FALSE(cpp.isString()); + EXPECT_FALSE(cpp.isVoid()); + EXPECT_FALSE(cpp.isNull()); + EXPECT_FALSE(cpp.isEmpty()); + EXPECT_FALSE(cpp.isObject()); + + cpp.Set(3.1415); + EXPECT_FALSE(cpp.isBool()); + EXPECT_FALSE(cpp.isInt32()); + EXPECT_TRUE(cpp.isDouble()); + EXPECT_TRUE(cpp.isNumber()); + EXPECT_FALSE(cpp.isString()); + EXPECT_FALSE(cpp.isVoid()); + EXPECT_FALSE(cpp.isNull()); + EXPECT_FALSE(cpp.isEmpty()); + EXPECT_FALSE(cpp.isObject()); + + cpp.Set("a string"); + EXPECT_FALSE(cpp.isBool()); + EXPECT_FALSE(cpp.isInt32()); + EXPECT_FALSE(cpp.isDouble()); + EXPECT_FALSE(cpp.isNumber()); + EXPECT_TRUE(cpp.isString()); + EXPECT_FALSE(cpp.isVoid()); + EXPECT_FALSE(cpp.isNull()); + EXPECT_FALSE(cpp.isEmpty()); + EXPECT_FALSE(cpp.isObject()); + + cpp.SetNull(); + EXPECT_FALSE(cpp.isBool()); + EXPECT_FALSE(cpp.isInt32()); + EXPECT_FALSE(cpp.isDouble()); + EXPECT_FALSE(cpp.isNumber()); + EXPECT_FALSE(cpp.isString()); + EXPECT_FALSE(cpp.isVoid()); + EXPECT_TRUE(cpp.isNull()); + EXPECT_TRUE(cpp.isEmpty()); + EXPECT_FALSE(cpp.isObject()); + + NPObject *obj = MakeVoidObject(); + cpp.Set(obj); + EXPECT_FALSE(cpp.isBool()); + EXPECT_FALSE(cpp.isInt32()); + EXPECT_FALSE(cpp.isDouble()); + EXPECT_FALSE(cpp.isNumber()); + EXPECT_FALSE(cpp.isString()); + EXPECT_FALSE(cpp.isVoid()); + EXPECT_FALSE(cpp.isNull()); + EXPECT_FALSE(cpp.isEmpty()); + EXPECT_TRUE(cpp.isObject()); + WebBindings::releaseObject(obj); + CheckObject(cpp); +} |