Bug 720771 - Companion testsuite. r=jorendorff

This commit is contained in:
David Rajchenbach-Teller 2012-04-11 17:55:21 -04:00
parent 9534b79926
commit 06d5789ee1
10 changed files with 1036 additions and 1 deletions

View File

@ -53,6 +53,7 @@ NO_DIST_INSTALL = 1
CPPSRCS = jsctypes-test.cpp \
jsctypes-test-errno.cpp \
jsctypes-test-finalizer.cpp \
$(NULL)
LOCAL_INCLUDES = \

View File

@ -0,0 +1,293 @@
#include "errno.h"
#include "jsctypes-test.h"
#include "jsctypes-test-finalizer.h"
#include "jsapi.h"
#if defined(XP_WIN)
#define snprintf _snprintf
#endif // defined(XP_WIN)
/**
* Shared infrastructure
*/
/**
* An array of integers representing resources.
* - 0: unacquired
* - 1: acquired
* - < 0: error, resource has been released several times.
*/
int *gFinalizerTestResources = NULL;
char **gFinalizerTestNames = NULL;
size_t gFinalizerTestSize;
void
test_finalizer_start(size_t size)
{
gFinalizerTestResources = new int[size];
gFinalizerTestNames = new char*[size];
gFinalizerTestSize = size;
for (size_t i = 0; i < size; ++i) {
gFinalizerTestResources[i] = 0;
gFinalizerTestNames[i] = NULL;
}
}
void
test_finalizer_stop()
{
delete[] gFinalizerTestResources;
}
/**
* Check if an acquired resource has been released
*/
bool
test_finalizer_resource_is_acquired(size_t i)
{
return gFinalizerTestResources[i] == 1;
}
// Resource type: size_t
// Acquire resource i
size_t
test_finalizer_acq_size_t(size_t i)
{
gFinalizerTestResources[i] = 1;
return i;
}
// Release resource i
void
test_finalizer_rel_size_t(size_t i)
{
if (--gFinalizerTestResources[i] < 0) {
MOZ_NOT_REACHED("Assertion failed");
}
}
size_t
test_finalizer_rel_size_t_return_size_t(size_t i)
{
if (-- gFinalizerTestResources[i] < 0) {
MOZ_NOT_REACHED("Assertion failed");
}
return i;
}
bool
test_finalizer_cmp_size_t(size_t a, size_t b)
{
return a==b;
}
// Resource type: int32_t
// Acquire resource i
int32_t
test_finalizer_acq_int32_t(size_t i)
{
gFinalizerTestResources[i] = 1;
return i;
}
// Release resource i
void
test_finalizer_rel_int32_t(int32_t i)
{
if (--gFinalizerTestResources[i] < 0) {
MOZ_NOT_REACHED("Assertion failed");
}
}
bool
test_finalizer_cmp_int32_t(int32_t a, int32_t b)
{
return a==b;
}
// Resource type: int64_t
// Acquire resource i
int64_t
test_finalizer_acq_int64_t(size_t i)
{
gFinalizerTestResources[i] = 1;
return i;
}
// Release resource i
void
test_finalizer_rel_int64_t(int64_t i)
{
if (-- gFinalizerTestResources[i] < 0) {
MOZ_NOT_REACHED("Assertion failed");
}
}
bool
test_finalizer_cmp_int64_t(int64_t a, int64_t b)
{
return a==b;
}
// Resource type: void*
// Acquire resource i
void*
test_finalizer_acq_ptr_t(size_t i)
{
gFinalizerTestResources[i] = 1;
return (void*)&gFinalizerTestResources[i];
}
// Release resource i
void
test_finalizer_rel_ptr_t(void *i)
{
int *as_int = (int*)i;
-- (*as_int);
if (*as_int < 0) {
MOZ_NOT_REACHED("Assertion failed");
}
}
bool
test_finalizer_cmp_ptr_t(void *a, void *b)
{
return a==b;
}
// Resource type: NULL
// Acquire resource i
void*
test_finalizer_acq_null_t(size_t i)
{
gFinalizerTestResources[0] = 1;//Always index 0
return NULL;
}
// Release resource i
void
test_finalizer_rel_null_t(void *i)
{
if (i != NULL) {
MOZ_NOT_REACHED("Assertion failed");
}
gFinalizerTestResources[0] --;
}
bool
test_finalizer_null_resource_is_acquired(size_t)
{
return gFinalizerTestResources[0] == 1;
}
bool
test_finalizer_cmp_null_t(void *a, void *b)
{
return a==b;
}
// Resource type: char*
// Acquire resource i
char*
test_finalizer_acq_string_t(int i)
{
gFinalizerTestResources[i] = 1;
if (!gFinalizerTestNames[i]) {
char* buf = new char[10];
snprintf(buf, 10, "%d", i);
gFinalizerTestNames[i] = buf;
return buf;
}
return gFinalizerTestNames[i];
}
// Release resource i
void
test_finalizer_rel_string_t(char *i)
{
int index = atoi(i);
if (index < 0 || index >= (int)gFinalizerTestSize) {
MOZ_NOT_REACHED("Assertion failed");
}
gFinalizerTestResources[index] --;
}
bool
test_finalizer_string_resource_is_acquired(size_t i)
{
return gFinalizerTestResources[i] == 1;
}
bool
test_finalizer_cmp_string_t(char *a, char *b)
{
return !strncmp(a, b, 10);
}
// Resource type: RECT
// Acquire resource i
RECT
test_finalizer_acq_struct_t(int i)
{
gFinalizerTestResources[i] = 1;
RECT result = { i, i, i, i };
return result;
}
// Release resource i
void
test_finalizer_rel_struct_t(RECT i)
{
int index = i.top;
if (index < 0 || index >= (int)gFinalizerTestSize) {
MOZ_NOT_REACHED("Assertion failed");
}
gFinalizerTestResources[index] --;
}
bool
test_finalizer_struct_resource_is_acquired(RECT i)
{
int index = i.top;
if (index < 0 || index >= (int)gFinalizerTestSize) {
MOZ_NOT_REACHED("Assertion failed");
}
return gFinalizerTestResources[index] == 1;
}
bool
test_finalizer_cmp_struct_t(RECT a, RECT b)
{
return a.top == b.top;
}
// Support for checking that we reject NULL finalizer
afun* test_finalizer_rel_null_function()
{
return NULL;
}
void
test_finalizer_rel_size_t_set_errno(size_t i)
{
if (-- gFinalizerTestResources[i] < 0) {
MOZ_NOT_REACHED("Assertion failed");
}
errno = 10;
}
void
reset_errno()
{
errno = 0;
}

View File

@ -0,0 +1,52 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jsapi.h"
#define EXPORT_CDECL(type) NS_EXPORT type
NS_EXTERN_C
{
EXPORT_CDECL(void) test_finalizer_start(size_t size);
EXPORT_CDECL(void) test_finalizer_stop();
EXPORT_CDECL(bool) test_finalizer_resource_is_acquired(size_t i);
EXPORT_CDECL(size_t) test_finalizer_acq_size_t(size_t i);
EXPORT_CDECL(void) test_finalizer_rel_size_t(size_t i);
EXPORT_CDECL(size_t) test_finalizer_rel_size_t_return_size_t(size_t i);
EXPORT_CDECL(bool) test_finalizer_cmp_size_t(size_t a, size_t b);
EXPORT_CDECL(int32_t) test_finalizer_acq_int32_t(size_t i);
EXPORT_CDECL(void) test_finalizer_rel_int32_t(int32_t i);
EXPORT_CDECL(bool) test_finalizer_cmp_int32_t(int32_t a, int32_t b);
EXPORT_CDECL(int64_t) test_finalizer_acq_int64_t(size_t i);
EXPORT_CDECL(void) test_finalizer_rel_int64_t(int64_t i);
EXPORT_CDECL(bool) test_finalizer_cmp_int64_t(int64_t a, int64_t b);
EXPORT_CDECL(void*) test_finalizer_acq_ptr_t(size_t i);
EXPORT_CDECL(void) test_finalizer_rel_ptr_t(void *i);
EXPORT_CDECL(bool) test_finalizer_cmp_ptr_t(void *a, void *b);
EXPORT_CDECL(char*) test_finalizer_acq_string_t(int i);
EXPORT_CDECL(void) test_finalizer_rel_string_t(char *i);
EXPORT_CDECL(bool) test_finalizer_cmp_string_t(char *a, char *b);
EXPORT_CDECL(void*) test_finalizer_acq_null_t(size_t i);
EXPORT_CDECL(void) test_finalizer_rel_null_t(void *i);
EXPORT_CDECL(bool) test_finalizer_cmp_null_t(void *a, void *b);
EXPORT_CDECL(bool) test_finalizer_null_resource_is_acquired(size_t i);
EXPORT_CDECL(RECT) test_finalizer_acq_struct_t(int i);
EXPORT_CDECL(void) test_finalizer_rel_struct_t(RECT i);
EXPORT_CDECL(bool) test_finalizer_cmp_struct_t(RECT a, RECT b);
typedef void (*afun)(size_t);
EXPORT_CDECL(afun*) test_finalizer_rel_null_function();
EXPORT_CDECL(void) test_finalizer_rel_size_t_set_errno(size_t i);
EXPORT_CDECL(void) reset_errno();
}

View File

@ -23,6 +23,7 @@
* Fredrik Larsson <nossralf@gmail.com>
* Mark Finkle <mark.finkle@gmail.com>, <mfinkle@mozilla.com>
* Dan Witte <dwitte@mozilla.com>
* David Rajchenbach-Teller <dteller@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -39,9 +40,15 @@
* ***** END LICENSE BLOCK ***** */
#include "jsctypes-test.h"
#include "jsapi.h"
#include "nsCRTGlue.h"
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#if defined(XP_WIN)
#define snprintf _snprintf
#endif // defined(XP_WIN)
template <typename T> struct ValueTraits {
static T literal() { return static_cast<T>(109.25); }
@ -403,4 +410,3 @@ test_vector_add_va_cdecl(PRUint8 num_vecs,
}
RECT data_rect = { -1, -2, 3, 4 };

View File

@ -23,6 +23,7 @@
* Fredrik Larsson <nossralf@gmail.com>
* Mark Finkle <mark.finkle@gmail.com>, <mfinkle@mozilla.com>
* Dan Witte <dwitte@mozilla.com>
* David Rajchenbach-Teller <dteller@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@ -77,3 +77,18 @@ function structural_check_eq_aux(a, b) {
}
);
}
function trigger_gc() {
dump("Triggering garbage-collection");
Components.utils.forceGC();
}
function must_throw(f) {
let has_thrown = false;
try {
f();
} catch (x) {
has_thrown = true;
}
do_check_true(has_thrown);
}

View File

@ -0,0 +1,385 @@
let TEST_SIZE = 100;
function run_test()
{
let library = open_ctypes_test_lib();
let start = library.declare("test_finalizer_start", ctypes.default_abi,
ctypes.void_t,
ctypes.size_t);
let stop = library.declare("test_finalizer_stop", ctypes.default_abi,
ctypes.void_t);
let status = library.declare("test_finalizer_resource_is_acquired",
ctypes.default_abi,
ctypes.bool,
ctypes.size_t);
let samples = [];
samples.push(
{
name: "size_t",
acquire: library.declare("test_finalizer_acq_size_t",
ctypes.default_abi,
ctypes.size_t,
ctypes.size_t),
release: library.declare("test_finalizer_rel_size_t",
ctypes.default_abi,
ctypes.void_t,
ctypes.size_t),
compare: library.declare("test_finalizer_cmp_size_t",
ctypes.default_abi,
ctypes.bool,
ctypes.size_t,
ctypes.size_t),
status: status
});
samples.push(
{
name: "size_t",
acquire: library.declare("test_finalizer_acq_size_t",
ctypes.default_abi,
ctypes.size_t,
ctypes.size_t),
release: library.declare("test_finalizer_rel_size_t_set_errno",
ctypes.default_abi,
ctypes.void_t,
ctypes.size_t),
compare: library.declare("test_finalizer_cmp_size_t",
ctypes.default_abi,
ctypes.bool,
ctypes.size_t,
ctypes.size_t),
status: status
});
samples.push(
{
name: "int32_t",
acquire: library.declare("test_finalizer_acq_int32_t",
ctypes.default_abi,
ctypes.int32_t,
ctypes.size_t),
release: library.declare("test_finalizer_rel_int32_t",
ctypes.default_abi,
ctypes.void_t,
ctypes.int32_t),
compare: library.declare("test_finalizer_cmp_int32_t",
ctypes.default_abi,
ctypes.bool,
ctypes.int32_t,
ctypes.int32_t),
status: status
}
);
samples.push(
{
name: "int64_t",
acquire: library.declare("test_finalizer_acq_int64_t",
ctypes.default_abi,
ctypes.int64_t,
ctypes.size_t),
release: library.declare("test_finalizer_rel_int64_t",
ctypes.default_abi,
ctypes.void_t,
ctypes.int64_t),
compare: library.declare("test_finalizer_cmp_int64_t",
ctypes.default_abi,
ctypes.bool,
ctypes.int64_t,
ctypes.int64_t),
status: status
}
);
samples.push(
{
name: "ptr",
acquire: library.declare("test_finalizer_acq_ptr_t",
ctypes.default_abi,
ctypes.PointerType(ctypes.void_t),
ctypes.size_t),
release: library.declare("test_finalizer_rel_ptr_t",
ctypes.default_abi,
ctypes.void_t,
ctypes.PointerType(ctypes.void_t)),
compare: library.declare("test_finalizer_cmp_ptr_t",
ctypes.default_abi,
ctypes.bool,
ctypes.void_t.ptr,
ctypes.void_t.ptr),
status: status
}
);
samples.push(
{
name: "string",
acquire: library.declare("test_finalizer_acq_string_t",
ctypes.default_abi,
ctypes.char.ptr,
ctypes.int),
release: library.declare("test_finalizer_rel_string_t",
ctypes.default_abi,
ctypes.void_t,
ctypes.char.ptr),
compare: library.declare("test_finalizer_cmp_string_t",
ctypes.default_abi,
ctypes.bool,
ctypes.char.ptr,
ctypes.char.ptr),
status: status
}
);
const rect_t = new ctypes.StructType("RECT",
[{ top : ctypes.int32_t },
{ left : ctypes.int32_t },
{ bottom: ctypes.int32_t },
{ right : ctypes.int32_t }]);
samples.push(
{
name: "struct",
acquire: library.declare("test_finalizer_acq_struct_t",
ctypes.default_abi,
rect_t,
ctypes.int),
release: library.declare("test_finalizer_rel_struct_t",
ctypes.default_abi,
ctypes.void_t,
rect_t),
compare: library.declare("test_finalizer_cmp_struct_t",
ctypes.default_abi,
ctypes.bool,
rect_t,
rect_t),
status: status
}
);
samples.push(
{
name: "size_t, release returns size_t",
acquire: library.declare("test_finalizer_acq_size_t",
ctypes.default_abi,
ctypes.size_t,
ctypes.size_t),
release: library.declare("test_finalizer_rel_size_t_return_size_t",
ctypes.default_abi,
ctypes.size_t,
ctypes.size_t),
compare: library.declare("test_finalizer_cmp_size_t",
ctypes.default_abi,
ctypes.bool,
ctypes.size_t,
ctypes.size_t),
status: status
}
);
samples.push(
{
name: "null",
acquire: library.declare("test_finalizer_acq_null_t",
ctypes.default_abi,
ctypes.PointerType(ctypes.void_t),
ctypes.size_t),
release: library.declare("test_finalizer_rel_null_t",
ctypes.default_abi,
ctypes.void_t,
ctypes.PointerType(ctypes.void_t)),
status: library.declare("test_finalizer_null_resource_is_acquired",
ctypes.default_abi,
ctypes.bool,
ctypes.size_t),
compare: library.declare("test_finalizer_cmp_null_t",
ctypes.default_abi,
ctypes.bool,
ctypes.void_t.ptr,
ctypes.void_t.ptr)
}
);
let tester = new ResourceTester(start, stop);
samples.forEach(
function(sample) {
dump("Executing finalization test for data "+sample.name+"\n");
tester.launch(TEST_SIZE, test_executing_finalizers, sample);
tester.launch(TEST_SIZE, test_do_not_execute_finalizers_on_referenced_stuff, sample);
tester.launch(TEST_SIZE, test_executing_dispose, sample);
tester.launch(TEST_SIZE, test_executing_forget, sample);
}
);
/*
* Following test deactivated: Cycle collection never takes place
* (see bug 727371)
tester.launch(TEST_SIZE, test_cycles, samples[0]);
*/
library.close();
}
// If only I could have Promises to test this :)
// There is only so much we can do at this stage,
// if we want to avoid tests overlapping.
function test_cycles(size, tc) {
// Now, restart this with unreferenced cycles
for (i = 0; i < size/2; ++i) {
let a = {
a: ctypes.CDataFinalizer(tc.acquire(i*2), tc.release),
b: {
b: ctypes.CDataFinalizer(tc.acquire(i*2+1), tc.release)
}
};
a.b.a = a;
}
do_test_pending();
Components.utils.schedulePreciseGC(
function() {
// Check that _something_ has been finalized
do_check_true(count_finalized(size, tc) > 0);
do_test_finished();
}
);
do_timeout(10000, do_throw);
}
function count_finalized(size, tc) {
let finalizedItems = 0;
for (let i = 0; i < size; ++i) {
if (!tc.status(i)) {
++finalizedItems;
}
}
return finalizedItems;
}
/**
* Test:
* - that (some) finalizers are executed;
* - that no finalizer is executed twice (this is done on the C side).
*/
function test_executing_finalizers(size, tc)
{
dump("test_executing_finalizers\n");
// Allocate |size| items without references
for (let i = 0; i < size; ++i) {
ctypes.CDataFinalizer(tc.acquire(i), tc.release);
}
trigger_gc(); // This should trigger some finalizations, hopefully all
// Check that _something_ has been finalized
do_check_true(count_finalized(size, tc) > 0);
}
/**
* Check that
* - |dispose| is executed properly
* - finalizers are not executed after |dispose|
*/
function test_executing_dispose(size, tc)
{
dump("test_executing_dispose\n");
let ref = [];
// Allocate |size| items with references
for (let i = 0; i < size; ++i) {
ref.push(ctypes.CDataFinalizer(tc.acquire(i), tc.release));
}
do_check_eq(count_finalized(size, tc), 0);
// Dispose of everything and make sure that everything has been cleaned up
ref.forEach(
function(v) {
v.dispose();
}
);
do_check_eq(count_finalized(size, tc), size);
// Remove references
ref = [];
// Re-acquireialize data and make sure that everything has been reinialized
for (i = 0; i < size; ++i) {
tc.acquire(i);
}
do_check_eq(count_finalized(size, tc), 0);
// Attempt to trigger finalizations, ensure that they do not take place
trigger_gc();
do_check_eq(count_finalized(size, tc), 0);
}
/**
* Check that
* - |forget| does not dispose
* - |forget| has the right content
* - finalizers are not executed after |forget|
*/
function test_executing_forget(size, tc)
{
dump("test_executing_forget\n");
let ref = [];
// Allocate |size| items with references
for (let i = 0; i < size; ++i) {
let original = tc.acquire(i);
let finalizer = ctypes.CDataFinalizer(original, tc.release);
ref.push(
{
original: original,
finalizer: finalizer
}
);
do_check_true(tc.compare(original, finalizer));
}
do_check_eq(count_finalized(size, tc), 0);
// Forget everything, making sure that we recover the original info
ref.forEach(
function(v) {
let original = v.original;
let recovered = v.finalizer.forget();
// Note: Cannot use do_check_eq on Uint64 et al.
do_check_true(tc.compare(original, recovered));
do_check_eq(original.constructor, recovered.constructor);
}
);
// Also make sure that we have not performed any clean up
do_check_eq(count_finalized(size, tc), 0);
// Remove references
ref = [];
// Attempt to trigger finalizations, ensure that they have no effect
trigger_gc();
do_check_eq(count_finalized(size, tc), 0);
}
/**
* Check that finalizers are not executed
*/
function test_do_not_execute_finalizers_on_referenced_stuff(size, tc)
{
dump("test_do_not_execute_finalizers_on_referenced_stuff\n");
let ref = [];
// Allocate |size| items without references
for (let i = 0; i < size; ++i) {
ref.push(ctypes.CDataFinalizer(tc.acquire(i), tc.release));
}
trigger_gc(); // This might trigger some finalizations, but it should not
// Check that _nothing_ has been finalized
do_check_eq(count_finalized(size, tc), 0);
// Clean up manually, lest leftover data interferes with following tests
ref.forEach(function(v) {
v.dispose();
});
ref = [];
trigger_gc();
}

View File

@ -0,0 +1,122 @@
try {
// We might be running without privileges, in which case it's up to the
// harness to give us the 'ctypes' object.
Components.utils.import("resource://gre/modules/ctypes.jsm");
} catch(e) {
}
let acquire, dispose, reset_errno, dispose_errno;
function run_test()
{
let library = open_ctypes_test_lib();
let start = library.declare("test_finalizer_start", ctypes.default_abi,
ctypes.void_t,
ctypes.size_t);
let stop = library.declare("test_finalizer_stop", ctypes.default_abi,
ctypes.void_t);
let tester = new ResourceTester(start, stop);
acquire = library.declare("test_finalizer_acq_size_t",
ctypes.default_abi,
ctypes.size_t,
ctypes.size_t);
dispose = library.declare("test_finalizer_rel_size_t",
ctypes.default_abi,
ctypes.void_t,
ctypes.size_t);
reset_errno = library.declare("reset_errno",
ctypes.default_abi,
ctypes.void_t);
dispose_errno = library.declare("test_finalizer_rel_size_t_set_errno",
ctypes.default_abi,
ctypes.void_t,
ctypes.size_t);
tester.launch(10, test_to_string);
tester.launch(10, test_to_source);
tester.launch(10, test_to_int);
tester.launch(10, test_errno);
}
/**
* Check that toString succeeds before/after forget/dispose.
*/
function test_to_string()
{
do_print("Starting test_to_string");
let a = ctypes.CDataFinalizer(acquire(0), dispose);
do_check_eq(a.toString(), "0");
a.forget();
do_check_eq(a.toString(), "[CDataFinalizer - empty]");
a = ctypes.CDataFinalizer(acquire(0), dispose);
a.dispose();
do_check_eq(a.toString(), "[CDataFinalizer - empty]");
}
/**
* Check that toSource succeeds before/after forget/dispose.
*/
function test_to_source()
{
do_print("Starting test_to_source");
let value = acquire(0);
let a = ctypes.CDataFinalizer(value, dispose);
do_check_eq(a.toSource(),
"ctypes.CDataFinalizer("
+ ctypes.size_t(value).toSource()
+", "
+dispose.toSource()
+")");
value = null;
a.forget();
do_check_eq(a.toSource(), "ctypes.CDataFinalizer()");
a = ctypes.CDataFinalizer(acquire(0), dispose);
a.dispose();
do_check_eq(a.toSource(), "ctypes.CDataFinalizer()");
}
/**
* Test conversion to int32
*/
function test_to_int()
{
let value = 2;
let wrapped, converted, finalizable;
wrapped = ctypes.int32_t(value);
finalizable= ctypes.CDataFinalizer(acquire(value), dispose);
converted = ctypes.int32_t(finalizable);
structural_check_eq(converted, wrapped);
structural_check_eq(converted, ctypes.int32_t(finalizable.forget()));
wrapped = ctypes.int64_t(value);
converted = ctypes.int64_t(ctypes.CDataFinalizer(acquire(value),
dispose));
structural_check_eq(converted, wrapped);
}
/**
* Test that dispose can change errno but finalization cannot
*/
function test_errno(size)
{
reset_errno();
do_check_eq(ctypes.errno, 0);
let finalizable = ctypes.CDataFinalizer(acquire(3), dispose_errno);
finalizable.dispose();
do_check_eq(ctypes.errno, 10);
reset_errno();
do_check_eq(ctypes.errno, 0);
for (let i = 0; i < size; ++i) {
finalizable = ctypes.CDataFinalizer(acquire(i), dispose_errno);
}
trigger_gc();
do_check_eq(ctypes.errno, 0);
}

View File

@ -0,0 +1,156 @@
try {
// We might be running without privileges, in which case it's up to the
// harness to give us the 'ctypes' object.
Components.utils.import("resource://gre/modules/ctypes.jsm");
} catch(e) {
}
let acquire, dispose, null_dispose, compare;
function run_test()
{
let library = open_ctypes_test_lib();
let start = library.declare("test_finalizer_start", ctypes.default_abi,
ctypes.void_t,
ctypes.size_t);
let stop = library.declare("test_finalizer_stop", ctypes.default_abi,
ctypes.void_t);
let tester = new ResourceTester(start, stop);
acquire = library.declare("test_finalizer_acq_size_t",
ctypes.default_abi,
ctypes.size_t,
ctypes.size_t);
dispose = library.declare("test_finalizer_rel_size_t",
ctypes.default_abi,
ctypes.void_t,
ctypes.size_t);
compare = library.declare("test_finalizer_cmp_size_t",
ctypes.default_abi,
ctypes.bool,
ctypes.size_t,
ctypes.size_t);
let type_afun = ctypes.FunctionType(ctypes.default_abi,
ctypes.void_t,
[ctypes.size_t]).ptr;
let null_dispose_maker =
library.declare("test_finalizer_rel_null_function",
ctypes.default_abi,
type_afun
);
null_dispose = null_dispose_maker();
tester.launch(10, test_double_dispose);
tester.launch(10, test_finalize_bad_construction);
tester.launch(10, test_null_dispose);
tester.launch(10, test_pass_disposed);
}
/**
* Testing construction of finalizers with wrong arguments.
*/
function test_finalize_bad_construction() {
// First argument does not match second
must_throw(function() { ctypes.CDataFinalizer({}, dispose); });
must_throw(function() { ctypes.CDataFinalizer(dispose, dispose); });
// Not enough arguments
must_throw(function() { ctypes.CDataFinalizer(init(0)); });
// Too many arguments
must_throw(function() { ctypes.CDataFinalizer(init(0), dispose, dispose); });
// Second argument is null
must_throw(function() { ctypes.CDataFinalizer(init(0), null); });
// Second argument is undefined
must_throw(function() {
let a;
ctypes.CDataFinalizer(init(0), a);
});
}
/**
* Test that forget/dispose can only take place once.
*/
function test_double_dispose() {
function test_one_combination(i, a, b) {
let v = ctypes.CDataFinalizer(acquire(i), dispose);
a(v);
must_throw(function() { b(v); } );
}
let call_dispose = function(v) {
v.dispose();
};
let call_forget = function(v) {
v.forget();
};
test_one_combination(0, call_dispose, call_dispose);
test_one_combination(1, call_dispose, call_forget);
test_one_combination(2, call_forget, call_dispose);
test_one_combination(3, call_forget, call_forget);
}
/**
* Test that nothing (too) bad happens when the finalizer is NULL
*/
function test_null_dispose()
{
let exception;
exception = false;
try {
let v = ctypes.CDataFinalizer(acquire(0), null_dispose);
} catch (x) {
exception = true;
}
do_check_true(exception);
}
/**
* Test that conversion of a disposed/forgotten CDataFinalizer to a C
* value fails nicely.
*/
function test_pass_disposed()
{
let exception, v;
exception = false;
v = ctypes.CDataFinalizer(acquire(0), dispose);
do_check_true(compare(v, 0));
v.forget();
try {
compare(v, 0);
} catch (x) {
exception = true;
}
do_check_true(exception);
exception = false;
v = ctypes.CDataFinalizer(acquire(0), dispose);
do_check_true(compare(v, 0));
v.dispose();
try {
compare(v, 0);
} catch (x) {
exception = true;
}
do_check_true(exception);
exception = false;
try {
ctypes.int32_t(ctypes.CDataFinalizer(v, dispose));
} catch (x) {
exception = true;
}
do_check_true(exception);
}

View File

@ -4,6 +4,10 @@ tail =
[test_errno.js]
[test_finalizer.js]
[test_finalizer_shouldfail.js]
[test_finalizer_shouldaccept.js]
[test_jsctypes.js]
# Bug 676989: test fails consistently on Android
fail-if = os == "android"