mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 01:48:05 +00:00
Bug 720771 - Companion testsuite. r=jorendorff
This commit is contained in:
parent
290bcaec25
commit
721862695a
@ -53,6 +53,7 @@ NO_DIST_INSTALL = 1
|
||||
|
||||
CPPSRCS = jsctypes-test.cpp \
|
||||
jsctypes-test-errno.cpp \
|
||||
jsctypes-test-finalizer.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
|
293
toolkit/components/ctypes/tests/jsctypes-test-finalizer.cpp
Normal file
293
toolkit/components/ctypes/tests/jsctypes-test-finalizer.cpp
Normal 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;
|
||||
}
|
||||
|
52
toolkit/components/ctypes/tests/jsctypes-test-finalizer.h
Normal file
52
toolkit/components/ctypes/tests/jsctypes-test-finalizer.h
Normal 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();
|
||||
|
||||
}
|
@ -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 };
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
385
toolkit/components/ctypes/tests/unit/test_finalizer.js
Normal file
385
toolkit/components/ctypes/tests/unit/test_finalizer.js
Normal 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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user