aboutsummaryrefslogtreecommitdiffstats
path: root/tests/cpp-unit-tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests/cpp-unit-tests')
-rw-r--r--tests/cpp-unit-tests/IcedTeaJavaRequestProcessorTest.cc416
-rw-r--r--tests/cpp-unit-tests/IcedTeaNPPluginTest.cc32
-rw-r--r--tests/cpp-unit-tests/IcedTeaPluginUtilsTest.cc4
-rw-r--r--tests/cpp-unit-tests/IcedTeaScriptablePluginObjectTest.cc33
-rw-r--r--tests/cpp-unit-tests/MemoryLeakDetector.h2
-rw-r--r--tests/cpp-unit-tests/browser_mock.cc56
-rw-r--r--tests/cpp-unit-tests/browser_mock.h4
-rw-r--r--tests/cpp-unit-tests/browser_mock_npidentifier.cc117
-rw-r--r--tests/cpp-unit-tests/browser_mock_npidentifier.h57
-rw-r--r--tests/cpp-unit-tests/checked_allocations.h6
-rw-r--r--tests/cpp-unit-tests/main.cc27
11 files changed, 731 insertions, 23 deletions
diff --git a/tests/cpp-unit-tests/IcedTeaJavaRequestProcessorTest.cc b/tests/cpp-unit-tests/IcedTeaJavaRequestProcessorTest.cc
new file mode 100644
index 0000000..517d5d0
--- /dev/null
+++ b/tests/cpp-unit-tests/IcedTeaJavaRequestProcessorTest.cc
@@ -0,0 +1,416 @@
+/* Copyright (C) 2013 Red Hat
+
+ This file is part of IcedTea.
+
+ IcedTea is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ IcedTea is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with IcedTea; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+#include <cstdio>
+
+#include <vector>
+#include <string>
+
+#include <npapi.h>
+
+#include <UnitTest++.h>
+
+#include "MemoryLeakDetector.h"
+
+#include "IcedTeaJavaRequestProcessor.h"
+
+/******************************************************************************
+ * Simple helper methods to keep the tests clean. *
+ ******************************************************************************/
+
+static const char* TEST_SOURCE = "[System]";
+
+static std::string checked_return(JavaResultData* result) {
+ CHECK(!result->error_occurred);
+ return *result->return_string;
+}
+
+// Packages
+
+static bool jrp_has_package(std::string package_name) {
+ JavaRequestProcessor processor;
+ JavaResultData* result = processor.hasPackage(0, package_name);
+ CHECK(!result->error_occurred);
+ return (result->return_identifier != 0);
+}
+
+// Classes
+
+static std::string jrp_find_class(std::string name) {
+ return checked_return(
+ JavaRequestProcessor().findClass(0, name)
+ );
+}
+
+// Object creation
+
+static std::string jrp_new_object_with_constructor(std::string class_id,
+ std::string method_id,
+ std::vector<std::string> args = std::vector<std::string>()) {
+ return checked_return(
+ JavaRequestProcessor().newObjectWithConstructor(TEST_SOURCE,
+ class_id, method_id, args)
+ );
+}
+
+static std::string jrp_new_array(std::string class_id, std::string len) {
+ return checked_return(
+ JavaRequestProcessor().newArray(class_id, len)
+ );
+}
+
+static std::string jrp_new_string(std::string str) {
+ return checked_return(
+ JavaRequestProcessor().newString(str)
+ );
+}
+
+static std::string jrp_new_object(std::string class_id,
+ std::vector<std::string> args = std::vector<std::string>()) {
+ return checked_return(
+ JavaRequestProcessor().newObject(TEST_SOURCE, class_id, args)
+ );
+}
+
+static std::string jrp_get_value(std::string object_id) {
+ return checked_return(
+ JavaRequestProcessor().getValue(object_id)
+ );
+}
+
+// Inheritance
+
+static bool jrp_is_instance_of(std::string object_id, std::string class_id) {
+ JavaRequestProcessor processor;
+ JavaResultData* result = processor.isInstanceOf(object_id, class_id);
+
+ CHECK(!result->error_occurred);
+ return (result->return_identifier != 0);
+}
+
+
+// Java methods operations.
+
+static std::string jrp_get_method_id(std::string class_id,
+ std::string method_name,
+ std::vector<std::string> args = std::vector<std::string>()) {
+ return checked_return(
+ JavaRequestProcessor().getMethodID(class_id,
+ browser_functions.getstringidentifier(method_name.c_str()), args)
+ );
+}
+
+static std::string jrp_get_static_method_id(std::string class_id,
+ std::string method_name,
+ std::vector<std::string> args = std::vector<std::string>()) {
+ return checked_return(
+ JavaRequestProcessor().getStaticMethodID(class_id,
+ browser_functions.getstringidentifier(method_name.c_str()), args)
+ );
+}
+
+static std::string jrp_call_method(std::string object_id,
+ std::string method_name, std::vector<std::string> args = std::vector<std::string>()) {
+ return checked_return(
+ JavaRequestProcessor().callMethod(TEST_SOURCE, object_id,
+ method_name, args)
+ );
+}
+
+static std::string jrp_call_static_method(std::string class_id,
+ std::string method_name, std::vector<std::string> args = std::vector<std::string>()) {
+ return checked_return(
+ JavaRequestProcessor().callStaticMethod(TEST_SOURCE, class_id,
+ method_name, args)
+ );
+}
+
+static std::string jrp_get_string(std::string object_id) {
+ return checked_return(
+ JavaRequestProcessor().getString(object_id)
+ );
+}
+
+static std::string jrp_get_class_id(std::string object_id) {
+ return checked_return(
+ JavaRequestProcessor().getClassID(object_id)
+ );
+}
+
+
+// Java field operations.
+
+static std::string jrp_get_field(std::string object_id,
+ std::string field_name) {
+ return checked_return(
+ JavaRequestProcessor().getField(TEST_SOURCE,
+ jrp_get_class_id(object_id), object_id, field_name)
+ );
+}
+
+static std::string jrp_get_field_id(std::string class_id,
+ std::string field_name) {
+ return checked_return(
+ JavaRequestProcessor().getFieldID(class_id, field_name)
+ );
+}
+
+static std::string jrp_get_static_field_id(std::string class_id,
+ std::string field_name) {
+ return checked_return(
+ JavaRequestProcessor().getStaticFieldID(class_id, field_name)
+ );
+}
+
+static std::string jrp_get_static_field(std::string class_id,
+ std::string field_name) {
+ return checked_return(
+ JavaRequestProcessor().getStaticField(TEST_SOURCE, class_id, field_name)
+ );
+}
+
+static std::string jrp_set_field(std::string object_id, std::string field_name,
+ std::string value_id) {
+ return checked_return(
+ JavaRequestProcessor().setField(TEST_SOURCE,
+ jrp_get_class_id(object_id), object_id, field_name, value_id)
+ );
+}
+
+static std::string jrp_set_static_field(std::string class_id, std::string field_name,
+ std::string value_id) {
+ return checked_return(
+ JavaRequestProcessor().setStaticField(TEST_SOURCE, class_id, field_name, value_id)
+ );
+}
+
+// Java array operations.
+
+static std::string jrp_set_slot(std::string object_id, std::string index,
+ std::string value_id) {
+ return checked_return(
+ JavaRequestProcessor().setSlot(object_id, index, value_id)
+ );
+}
+
+static std::string jrp_get_slot(std::string object_id, std::string index) {
+ return checked_return(
+ JavaRequestProcessor().getSlot(object_id, index)
+ );
+}
+
+static std::string jrp_get_array_length(std::string object_id) {
+ return checked_return(
+ JavaRequestProcessor().getArrayLength(object_id)
+ );
+}
+
+// Result of toString()
+
+static std::string jrp_get_to_string_value(std::string object_id) {
+ return checked_return(
+ JavaRequestProcessor().getToStringValue(object_id)
+ );
+}
+
+/******************************************************************************
+ * Compound helper methods. *
+ ******************************************************************************/
+
+static NPP_t dummy_npp = {0,0};
+
+static std::string create_java_integer(int value) {
+ // Prepare a java integer object with the value 1
+ NPVariant integer_variant;
+ std::string integer_id;
+ INT32_TO_NPVARIANT(value, integer_variant);
+ createJavaObjectFromVariant(&dummy_npp, integer_variant, &integer_id);
+ return integer_id;
+}
+
+static std::string create_null() {
+ // Prepare a null object
+ NPVariant null_variant;
+ std::string null_id;
+ NULL_TO_NPVARIANT(null_variant);
+ createJavaObjectFromVariant(&dummy_npp, null_variant, &null_id);
+ return null_id;
+}
+
+static NPVariant java_result_to_variant(std::string object_id) {
+ NPVariant variant;
+ IcedTeaPluginUtilities::javaResultToNPVariant(&dummy_npp, &object_id, &variant);
+ return variant;
+}
+
+/* Call the no-argument constructor of an object */
+static std::string jrp_noarg_construct(std::string classname) {
+ std::string class_id = jrp_find_class(classname);
+ std::string constructor_id = jrp_get_method_id(class_id, "<init>");
+ return jrp_new_object_with_constructor(class_id, constructor_id);
+}
+
+
+/******************************************************************************
+ * Test cases. Note that the tests exercise a variety of functions to first *
+ * create the appropriate conditions for the intended test. *
+ ******************************************************************************/
+
+SUITE(JavaRequestProcessor) {
+
+ TEST(callMethod) {
+ std::string object_id = jrp_noarg_construct("java.lang.Object");
+ std::string tostring_result = jrp_get_string(
+ jrp_call_method(object_id, "toString"));
+ const char substr[] = "java.lang.Object@";
+ // Check that the result of toString is as expected
+ CHECK(strncmp(tostring_result.c_str(), substr, strlen(substr)) == 0);
+ }
+
+ /* Create a java.awt.Point, since it is one of the few standard classes with public fields. */
+ TEST(getField_and_setField) {
+ std::string object_id = jrp_noarg_construct("java.awt.Point");
+
+ // Set the field 'x' to 1
+ jrp_set_field(object_id, "x", create_java_integer(1));
+
+ // Get the field 'x'
+ NPVariant field_value = java_result_to_variant(jrp_get_field(object_id, "x"));
+
+ // Ensure that the received field is 1
+ CHECK(NPVARIANT_IS_INT32(field_value) && NPVARIANT_TO_INT32(field_value) == 1);
+ }
+
+ TEST(getStaticField_and_setStaticField) {
+ // One of the few classes with a public & non-final static field that we can tinker with.
+ // If it moves, this test will fail, in which-case this test should be updated to another appropriate field.
+ std::string class_id = jrp_find_class("net.sourceforge.jnlp.controlpanel.DebuggingPanel");
+ std::string properties_id = jrp_get_static_field(class_id, "properties");
+
+ // Check that the field is initially a non-null object
+ NPVariant sh_variant = java_result_to_variant(properties_id);
+ CHECK(!NPVARIANT_IS_NULL(sh_variant) && NPVARIANT_IS_OBJECT(sh_variant));
+ browser_functions.releasevariantvalue(&sh_variant);
+
+ jrp_set_static_field(class_id, "properties", create_null());
+ sh_variant = java_result_to_variant(jrp_get_static_field(class_id, "properties"));
+ CHECK(NPVARIANT_IS_NULL(sh_variant));
+
+ // Reset the field to its original contents
+ jrp_set_static_field(class_id, "properties", properties_id);
+ sh_variant = java_result_to_variant(jrp_get_static_field(class_id, "properties"));
+ CHECK(!NPVARIANT_IS_NULL(sh_variant) && NPVARIANT_IS_OBJECT(sh_variant));
+ browser_functions.releasevariantvalue(&sh_variant);
+ }
+
+ TEST(arrayIndexing) {
+ const int ARRAY_LEN = 1;
+
+ // We will create an Integer array of ARRAY_LEN
+ std::vector<std::string> args;
+ args.push_back(jrp_find_class("java.lang.Integer"));
+ args.push_back(create_java_integer(ARRAY_LEN));
+
+ // Create an array 'the hard way' (ie not using 'newArray') to test more of the API
+ std::string array_id = jrp_call_static_method(jrp_find_class("java.lang.reflect.Array"), "newInstance", args);
+
+ // Attempt to set the first element to 1
+ jrp_set_slot(array_id, "0", create_java_integer(1));
+ // Note we get an integer _object_, not a plain int literal
+ std::string integer_id = jrp_get_slot(array_id, "0");
+ NPVariant unboxed_slot_value = java_result_to_variant(jrp_call_method(integer_id, "intValue"));
+
+ // Ensure that the received slot is 1
+ CHECK(NPVARIANT_IS_INT32(unboxed_slot_value) && NPVARIANT_TO_INT32(unboxed_slot_value) == 1);
+ }
+
+ // Also exercises 'getToStringValue'
+ TEST(newObject) {
+ std::string object_id = jrp_new_object(jrp_find_class("java.lang.Object"));
+ const char substr[] = "java.lang.Object@";
+ // Check that the result of toString is as expected
+ CHECK(strncmp(jrp_get_to_string_value(object_id).c_str(), substr, strlen(substr)) == 0);
+ }
+
+ TEST(hasPackage) {
+ CHECK(jrp_has_package("java.lang"));
+ CHECK(!jrp_has_package("not.an.icedtea_web.package"));
+ }
+
+ TEST(newArray) {
+ const char ARRAY_LEN[] = "10";
+ std::string array_id = jrp_new_array(jrp_find_class("java.lang.Integer"), ARRAY_LEN);
+ CHECK_EQUAL(ARRAY_LEN, jrp_get_array_length(array_id));
+ }
+
+ TEST(newString) {
+ const char TEST_STRING[] = "foobar";
+ std::string string_id = jrp_new_string(TEST_STRING);
+ CHECK_EQUAL(TEST_STRING, jrp_get_string(string_id));
+ CHECK_EQUAL(TEST_STRING, jrp_get_to_string_value(string_id));
+ }
+
+ // Can only really do sanity checks with given API
+ TEST(getFieldID_getStaticFieldID) {
+ CHECK(!jrp_get_field_id(jrp_find_class("java.awt.Point"), "x").empty());
+ CHECK(!jrp_get_static_field_id(jrp_find_class("java.lang.Integer"), "MAX_VALUE").empty());
+ }
+
+ // Can only really do sanity checks with given API
+ TEST(getStaticMethodID) {
+ std::string class_id = jrp_find_class("java.lang.Integer");
+
+ std::vector<std::string> argtypes;
+ argtypes.push_back("Ljava.lang.String;");
+
+ CHECK(!jrp_get_static_method_id(class_id, "valueOf", argtypes).empty());
+ }
+
+ TEST(isInstanceOf) {
+ std::string point_id = jrp_noarg_construct("java.awt.Point");
+ std::string object_class_id = jrp_find_class("java.lang.Object");
+ CHECK(jrp_is_instance_of(point_id, object_class_id));
+ }
+
+ // Wasn't sure what the point of this method is to be honest, but it is used.
+ // Here it simply returns back a passed string object.
+ TEST(getValue) {
+ const char TEST_STRING[] = "foobar";
+
+ std::string str = jrp_get_string(jrp_get_value(jrp_new_string(TEST_STRING)));
+ CHECK_EQUAL(TEST_STRING, str);
+ }
+}
diff --git a/tests/cpp-unit-tests/IcedTeaNPPluginTest.cc b/tests/cpp-unit-tests/IcedTeaNPPluginTest.cc
index 1633d6b..6fc0bf9 100644
--- a/tests/cpp-unit-tests/IcedTeaNPPluginTest.cc
+++ b/tests/cpp-unit-tests/IcedTeaNPPluginTest.cc
@@ -40,7 +40,10 @@
#include <UnitTest++.h>
+#include "MemoryLeakDetector.h"
+
#include "IcedTeaNPPlugin.h"
+#include "IcedTeaScriptablePluginObject.h"
#include "IcedTeaPluginUtils.h"
TEST(NP_GetMIMEDescription) {
@@ -51,19 +54,38 @@ TEST(NP_GetMIMEDescription) {
/* Not normally exposed */
std::vector<std::string*>* get_jvm_args();
-extern gchar* in_pipe_name;
-extern gchar* out_pipe_name;
TEST(get_jvm_args) {
- in_pipe_name = (gchar*)"inpipe";
- out_pipe_name = (gchar*)"outpipe";
-
std::vector<std::string*>* args = get_jvm_args();
CHECK(args != NULL);
IcedTeaPluginUtilities::freeStringPtrVector(args);
}
+
+static IcedTeaScriptableJavaPackageObject* get_scriptable_package_object() {
+ NPP_t instance = { /*Plugin data*/plugin_data_new(), /* Browser data*/0 };
+
+ /* Get the packages object (since instance.pdata->is_applet_instance == false) */
+ NPObject* obj = get_scriptable_object(&instance);
+
+ /* Make sure we got an IcedTeaScriptableJavaPackageObject */
+ CHECK(obj->_class->deallocate == IcedTeaScriptableJavaPackageObject::deAllocate);
+
+ plugin_data_destroy(&instance);
+ return (IcedTeaScriptableJavaPackageObject*)obj;
+}
+
+TEST(get_scriptable_object) {
+ MemoryLeakDetector leak_detector;
+ // We test without an applet context, pending mocking of applet instances.
+ IcedTeaScriptableJavaPackageObject* obj = get_scriptable_package_object(); // Calls get_scriptable_object
+
+ browser_functions.releaseobject(obj);
+
+ CHECK(leak_detector.memory_leaks() == 0);
+}
+
TEST(NP_GetValue) {
void* __unused = NULL;
gchar* char_value = NULL;
diff --git a/tests/cpp-unit-tests/IcedTeaPluginUtilsTest.cc b/tests/cpp-unit-tests/IcedTeaPluginUtilsTest.cc
index 7df0a1e..ac0e0d3 100644
--- a/tests/cpp-unit-tests/IcedTeaPluginUtilsTest.cc
+++ b/tests/cpp-unit-tests/IcedTeaPluginUtilsTest.cc
@@ -86,11 +86,11 @@ TEST(NPVariantStringCopy) {
}
TEST(NPIdentifierAsString) {
- // NB: Mocked definition of 'utf8fromidentifier' simply reads NPIdentifier as a char* string.
const char test_string[] = "foobar";
MemoryLeakDetector leak_detector;
/* Ensure destruction */{
- std::string str = IcedTeaPluginUtilities::NPIdentifierAsString((NPIdentifier)test_string);
+ std::string str = IcedTeaPluginUtilities::NPIdentifierAsString(
+ browser_functions.getstringidentifier(test_string));
CHECK_EQUAL(test_string, str);
}
CHECK_EQUAL(0, leak_detector.memory_leaks());
diff --git a/tests/cpp-unit-tests/IcedTeaScriptablePluginObjectTest.cc b/tests/cpp-unit-tests/IcedTeaScriptablePluginObjectTest.cc
index 9de0bbd..bb2b376 100644
--- a/tests/cpp-unit-tests/IcedTeaScriptablePluginObjectTest.cc
+++ b/tests/cpp-unit-tests/IcedTeaScriptablePluginObjectTest.cc
@@ -95,4 +95,37 @@ SUITE(IcedTeaScriptableJavaPackageObject) {
browser_functions.releaseobject(obj);
CHECK(leak_detector.memory_leaks() == 0);
}
+
+ static NPVariant np_checked_get(NPObject* obj, const char* identifier) {
+ NPVariant result;
+ CHECK(browser_functions.getproperty(&dummy_npp, obj, browser_functions.getstringidentifier(identifier), &result));
+ return result;
+ }
+
+ /* NOTICE: Requires icedtea-web Java-side to be running!
+ * Loads java.lang.Integer.MAX_VALUE */
+ TEST(getProperty) {
+ MemoryLeakDetector leak_detector;
+ /* Ensure destruction */{
+ /* Get the 'root' package */
+ NPObject* obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_package_object(&dummy_npp, "");
+ // Look up java.lang.Integer.MAX_VALUE
+ NPVariant java_result = np_checked_get(obj, "java");
+ NPVariant lang_result = np_checked_get(NPVARIANT_TO_OBJECT(java_result), "lang");
+ NPVariant integer_result = np_checked_get(NPVARIANT_TO_OBJECT(lang_result), "Integer");
+ NPVariant max_value_result = np_checked_get(NPVARIANT_TO_OBJECT(integer_result), "MAX_VALUE");
+
+ // Check that it is indeed equal to 2147483647
+ CHECK(NPVARIANT_IS_INT32(max_value_result));
+ CHECK_EQUAL(2147483647, NPVARIANT_TO_INT32(max_value_result));
+
+ browser_functions.releasevariantvalue(&java_result);
+ browser_functions.releasevariantvalue(&lang_result);
+ browser_functions.releasevariantvalue(&integer_result);
+ browser_functions.releasevariantvalue(&max_value_result);
+
+ browser_functions.releaseobject(obj);
+ }
+ CHECK(leak_detector.memory_leaks() == 0);
+ }
}
diff --git a/tests/cpp-unit-tests/MemoryLeakDetector.h b/tests/cpp-unit-tests/MemoryLeakDetector.h
index 2bd5e9c..d457cb7 100644
--- a/tests/cpp-unit-tests/MemoryLeakDetector.h
+++ b/tests/cpp-unit-tests/MemoryLeakDetector.h
@@ -42,6 +42,7 @@
#define MEMORYLEAKDETECTOR_H_
#include <cstdio>
+#include "browser_mock.h"
#include "checked_allocations.h"
#include "IcedTeaPluginUtils.h"
@@ -69,7 +70,6 @@ public:
return cpp_leaks + npapi_leaks;
}
-private:
static void reset_global_state() {
/* Clears allocations caused by storeInstanceID */
IcedTeaPluginUtilities::clearInstanceIDs();
diff --git a/tests/cpp-unit-tests/browser_mock.cc b/tests/cpp-unit-tests/browser_mock.cc
index 8724687..32027f3 100644
--- a/tests/cpp-unit-tests/browser_mock.cc
+++ b/tests/cpp-unit-tests/browser_mock.cc
@@ -36,17 +36,26 @@
// Browser mock functions. Add more as needed.
+#include <new>
+#include <map>
#include <cstring>
+
+#include <npapi.h>
+
#include "checked_allocations.h"
#include "UnitTest++.h"
#include "browser_mock.h"
+#include "browser_mock_npidentifier.h"
-#include "IcedTeaNPPlugin.h"
+// 'Browser' global data
+// Stores NPAPI allocations
static AllocationSet __allocations;
+// Mocked functions
+
// It is expected that these will only run during a unit test
static void* mock_memalloc(uint32_t size) {
void* mem = malloc(size);
@@ -78,6 +87,15 @@ static void mock_releaseobject(NPObject* obj) {
}
}
+static void mock_releasevariantvalue(NPVariant* variant) {
+ if (variant->type == NPVariantType_String) {
+ /* Only string and object values require freeing */
+ mock_memfree((void*)variant->value.stringValue.UTF8Characters);
+ } else if (variant->type == NPVariantType_Object) {
+ mock_releaseobject(variant->value.objectValue);
+ }
+}
+
static NPObject* mock_createobject(NPP instance, NPClass* np_class) {
NPObject* obj;
if (np_class->allocate) {
@@ -90,17 +108,26 @@ static NPObject* mock_createobject(NPP instance, NPClass* np_class) {
return obj;
}
-static NPUTF8* mock_utf8fromidentifier(NPIdentifier id) {
- // Treat NPIdentifier (== void pointer) as a pointer to characters for simplicity
- const NPUTF8* str = (const NPUTF8*) id;
- // We expect this string to be freed with 'memfree'
- NPUTF8* copy = (NPUTF8*) mock_memalloc(strlen(str) + 1);
- memcpy(copy, str, strlen(str) + 1);
- return copy;
+static bool mock_getproperty(NPP npp, NPObject* obj, NPIdentifier property_name, NPVariant* result) {
+ if (obj->_class->getProperty) {
+ return obj->_class->getProperty(obj, property_name, result);
+ } else {
+ return false;
+ }
}
-void browsermock_setup_functions() {
+static bool mock_setproperty(NPP npp, NPObject* obj, NPIdentifier property_name, const NPVariant* value) {
+ if (obj->_class->setProperty) {
+ return obj->_class->setProperty(obj, property_name, value);
+ } else {
+ return false;
+ }
+}
+
+NPNetscapeFuncs browsermock_create_table() {
+ NPNetscapeFuncs browser_functions;
memset(&browser_functions, 0, sizeof(NPNetscapeFuncs));
+ browser_functions.size = sizeof(NPNetscapeFuncs);
browser_functions.memalloc = &mock_memalloc;
browser_functions.memfree = &mock_memfree;
@@ -108,7 +135,16 @@ void browsermock_setup_functions() {
browser_functions.createobject = &mock_createobject;
browser_functions.retainobject = &mock_retainobject;
browser_functions.releaseobject = &mock_releaseobject;
- browser_functions.utf8fromidentifier = &mock_utf8fromidentifier;
+ browser_functions.releasevariantvalue = &mock_releasevariantvalue;
+
+ browser_functions.setproperty = &mock_setproperty;
+ browser_functions.getproperty = &mock_getproperty;
+
+ browser_functions.utf8fromidentifier = &browsermock_utf8fromidentifier;
+ browser_functions.getstringidentifier = &browsermock_getstringidentifier;
+ browser_functions.identifierisstring = &browsermock_identifierisstring;
+
+ return browser_functions;
}
void browsermock_clear_state() {
diff --git a/tests/cpp-unit-tests/browser_mock.h b/tests/cpp-unit-tests/browser_mock.h
index d936215..ac38813 100644
--- a/tests/cpp-unit-tests/browser_mock.h
+++ b/tests/cpp-unit-tests/browser_mock.h
@@ -43,7 +43,9 @@
#ifndef __BROWSER_MOCK_H__
#define __BROWSER_MOCK_H__
-void browsermock_setup_functions();
+#include <npfunctions.h>
+
+NPNetscapeFuncs browsermock_create_table();
void browsermock_clear_state();
int browsermock_unfreed_allocations();
diff --git a/tests/cpp-unit-tests/browser_mock_npidentifier.cc b/tests/cpp-unit-tests/browser_mock_npidentifier.cc
new file mode 100644
index 0000000..736d9a5
--- /dev/null
+++ b/tests/cpp-unit-tests/browser_mock_npidentifier.cc
@@ -0,0 +1,117 @@
+/* Copyright (C) 2013 Red Hat
+
+ This file is part of IcedTea.
+
+ IcedTea is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ IcedTea is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with IcedTea; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+#include <cstdlib>
+
+#include <map>
+
+#include "IcedTeaNPPlugin.h"
+#include "checked_allocations.h"
+#include "browser_mock_npidentifier.h"
+
+struct MockedNPIdentifier_t; // foward declare
+typedef std::basic_string<char, std::char_traits<char>, SafeAllocator> SafeString;
+typedef std::map<int, MockedNPIdentifier_t*, std::less<int>, SafeAllocator> SafeIntToIDMap;
+typedef std::map<SafeString, MockedNPIdentifier_t*, std::less<SafeString>, SafeAllocator> SafeStringToIDMap;
+
+
+// Handles creation of NPIdentifier
+
+// Carefully avoids operator new so as not to interfere with leak detection.
+// This mimics browser internal state.
+struct MockedNPIdentifier_t {
+ SafeString string;
+ int integer;
+ bool is_integer; // If false, it is a string
+
+ // Carefully avoids operator new so as not to interfere with leak detection
+ static MockedNPIdentifier_t* safe_allocate(SafeString str) {
+ MockedNPIdentifier_t* mem = (MockedNPIdentifier_t*)malloc(sizeof(MockedNPIdentifier_t));
+ new (&mem->string) SafeString(str);
+ mem->integer = -1;
+ mem->is_integer = false;
+ return mem;
+ }
+
+ // Carefully avoids operator new so as not to interfere with leak detection
+ static MockedNPIdentifier_t* safe_allocate(int i) {
+ MockedNPIdentifier_t* mem = (MockedNPIdentifier_t*) malloc(
+ sizeof(MockedNPIdentifier_t));
+ new (&mem->string) SafeString();
+ mem->integer = i;
+ mem->is_integer = true;
+ return mem;
+ }
+};
+
+// Mimics global browser data. OK if not cleared in-between tests, does not change semantics.
+// Used to ensure NPIdentifiers are unique. Never freed.
+static SafeIntToIDMap __np_int_identifiers;
+static SafeStringToIDMap __np_string_identifiers;
+
+// Carefully avoids operator new so as not to interfere with leak detection
+NPIdentifier browsermock_getstringidentifier(const NPUTF8* name) {
+ SafeString safe_copy(name);
+ if (__np_string_identifiers.find(safe_copy) == __np_string_identifiers.end()) {
+ __np_string_identifiers[safe_copy] = MockedNPIdentifier_t::safe_allocate(safe_copy);
+ }
+ return __np_string_identifiers[safe_copy];
+}
+
+// Carefully avoids operator new so as not to interfere with leak detection
+NPIdentifier browsermock_getintidentifier(int i) {
+ if (__np_int_identifiers.find(i) == __np_int_identifiers.end()) {
+ __np_int_identifiers[i] = MockedNPIdentifier_t::safe_allocate(i);
+ }
+ return __np_int_identifiers[i];
+}
+
+bool browsermock_identifierisstring(NPIdentifier identifier) {
+ MockedNPIdentifier_t* contents = (MockedNPIdentifier_t*)identifier;
+ return !contents->is_integer;
+}
+
+NPUTF8* browsermock_utf8fromidentifier(NPIdentifier identifier) {
+ MockedNPIdentifier_t* contents = (MockedNPIdentifier_t*)identifier;
+ if (contents->is_integer) {
+ return NULL;
+ }
+
+ // We expect this string to be freed with 'memfree'
+ NPUTF8* copy = (NPUTF8*) browser_functions.memalloc(contents->string.size() + 1);
+ memcpy(copy, contents->string.c_str(), contents->string.size() + 1);
+ return copy;
+}
diff --git a/tests/cpp-unit-tests/browser_mock_npidentifier.h b/tests/cpp-unit-tests/browser_mock_npidentifier.h
new file mode 100644
index 0000000..d477fef
--- /dev/null
+++ b/tests/cpp-unit-tests/browser_mock_npidentifier.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2013 Red Hat
+
+ This file is part of IcedTea.
+
+ IcedTea is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ IcedTea is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with IcedTea; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+/*
+ * browser_mock_npidentifier.h:
+ * Handles NPAPI functions related to NPIdentifier, NPIdentifier has the following constraints:
+ * - Unique for each integer & string
+ * - Should not interfere with leak detection, so use malloc-based allocators (specified by templates) everywhere.
+ */
+
+#ifndef __BROWSER_MOCK_NPIDENTIFIER_H__
+#define __BROWSER_MOCK_NPIDENTIFIER_H__
+
+#include <string>
+#include <npfunctions.h>
+
+NPIdentifier browsermock_getstringidentifier(const NPUTF8* name);
+NPIdentifier browsermock_getintidentifier(int i);
+
+bool browsermock_identifierisstring(NPIdentifier identifier);
+
+NPUTF8* browsermock_utf8fromidentifier(NPIdentifier identifier);
+
+#endif // __BROWSER_MOCK_NPIDENTIFIER_H__
diff --git a/tests/cpp-unit-tests/checked_allocations.h b/tests/cpp-unit-tests/checked_allocations.h
index 0c9ce04..299c769 100644
--- a/tests/cpp-unit-tests/checked_allocations.h
+++ b/tests/cpp-unit-tests/checked_allocations.h
@@ -39,6 +39,7 @@
#ifndef CHECKED_ALLOCATIONS_H_
#define CHECKED_ALLOCATIONS_H_
+#include <string>
#include <set>
#include <cstdio>
#include <exception>
@@ -46,8 +47,9 @@
#include <cstdlib>
#include <ext/malloc_allocator.h> //GNU extension
-// Plays nice with custom-defined operator new
-typedef std::set<void*, std::less<void*>, __gnu_cxx::malloc_allocator<void*> > AllocationSet;
+// Classes that play nice with custom-defined operator new by using 'vanilla' malloc
+typedef __gnu_cxx::malloc_allocator<void*> SafeAllocator;
+typedef std::set<void*, std::less<void*>, SafeAllocator> AllocationSet;
int cpp_unfreed_allocations();
diff --git a/tests/cpp-unit-tests/main.cc b/tests/cpp-unit-tests/main.cc
index d7e71f6..c050bbb 100644
--- a/tests/cpp-unit-tests/main.cc
+++ b/tests/cpp-unit-tests/main.cc
@@ -42,7 +42,11 @@
#include <UnitTest++.h>
#include <TestReporter.h>
+#include <npfunctions.h>
+
+#include "IcedTeaNPPlugin.h"
#include "browser_mock.h"
+#include "MemoryLeakDetector.h"
#include "checked_allocations.h"
using namespace UnitTest;
@@ -56,6 +60,12 @@ static std::string full_testname(const TestDetails& details) {
}
}
+// Important for testing purposes of eg leaks between tests
+static void reset_global_state() {
+ browsermock_clear_state();
+ MemoryLeakDetector::reset_global_state();
+}
+
class IcedteaWebUnitTestReporter: public TestReporter {
public:
@@ -66,7 +76,7 @@ public:
}
virtual void ReportTestStart(const TestDetails& test) {
- browsermock_clear_state();
+ reset_global_state();
pretest_allocs = cpp_unfreed_allocations();
did_finish_correctly = true;
}
@@ -84,6 +94,7 @@ public:
virtual void ReportTestFinish(const TestDetails& details,
float secondsElapsed) {
+ reset_global_state();
int posttest_allocs = cpp_unfreed_allocations();
std::string testname = full_testname(details);
@@ -126,8 +137,20 @@ static int run_icedtea_web_unit_tests() {
True() /*All tests*/, 0 /*No time limit*/);
}
+/* Spawns the Java-side of the plugin, create request processing threads,
+ * and sets up a mocked 'browser' environment. */
+static void initialize_plugin_components() {
+ NPNetscapeFuncs mocked_browser_functions = browsermock_create_table();
+ NPPluginFuncs unused_plugin_functions;
+ memset(&unused_plugin_functions, 0, sizeof(NPPluginFuncs));
+ unused_plugin_functions.size = sizeof(NPPluginFuncs);
+
+ NP_Initialize (&mocked_browser_functions, &unused_plugin_functions);
+ start_jvm_if_needed();
+}
+
int main() {
- browsermock_setup_functions();
+ initialize_plugin_components();
int exitcode = run_icedtea_web_unit_tests();