pike.git/
src/
testsuite.in
Branch:
Tag:
Non-build tags
All tags
No tags
2000-06-09
2000-06-09 22:17:28 by Martin Stjernholm <mast@lysator.liu.se>
5953b2df9292ba14d2ec8c61ac33d38b154291af (
498
lines) (+
497
/-
1
)
[
Show
|
Annotate
]
Branch:
7.9
A bunch of new gc tests.
Rev: src/testsuite.in:1.298
1:
-
test_true([["$Id: testsuite.in,v 1.
297
2000/06/
06
22:
51
:
55
hubbe
Exp $"]]);
+
test_true([["$Id: testsuite.in,v 1.
298
2000/06/
09
22:
17
:
28
mast
Exp $"]]);
cond([[all_constants()->_verify_internals]], [[
1677:
test_any([[object o=class c {object o;}(); o->o=o; gc(); o=0; return gc() > 0; ]],1); test_any([[mapping m=([]); m[m]=m; gc(); m=0; return gc() > 0; ]],1); test_any([[multiset m=(<>); m[m]=1; gc(); m=0; return gc() > 0; ]],1);
+
test_any([[{
+
#if !constant (_debug)
+
int _debug (int d) {return 0;};
+
#endif
+
// Must turn off debug in this test or else we'll get extra
+
// references to p in the backlog.
+
int dlevel = _debug (0);
+
program p=compile_string("constant a=({0});");
+
object o=p();
+
o->a[0]=p;
+
gc();
+
p=o=0;
+
_debug (dlevel);
+
return gc() > 0;
+
}]], 1);
test_any([[gc(); int q=lambda() { mixed foo; foo=lambda() { return foo; }; return 1; }();
1755:
} }()->test(); ]])
+
+
test_any([[{
+
array a = ({({0})}); a[0][0] = a;
+
gc(); a = 0; return gc() > 0;
+
}]], 1)
+
+
test_any([[{
+
class Dead {object o;};
+
object o = Dead(); o->o = Dead(); o->o->o = o;
+
gc(); o = 0; return gc() > 0;
+
}]], 1)
+
test_any([[{
+
class Live {object o; void destroy() {}};
+
object o = Live(); o->o = Live(); o->o->o = o;
+
gc(); o = 0; return gc() > 0;
+
}]], 1)
+
test_any([[{
+
class Dead {object o;};
+
class Live {object o; void destroy() {}};
+
object o = Dead(); o->o = Live(); o->o->o = o;
+
gc(); o = 0; return gc() > 0;
+
}]], 1)
+
test_any([[{
+
class Dead {object o;};
+
class Live {object o; void destroy() {}};
+
object o = Live(); o->o = Dead(); o->o->o = o;
+
gc(); o = 0; return gc() > 0;
+
}]], 1)
+
+
test_any_equal([[{
+
class Live {object o; void destroy() {}};
+
array a = set_weak_flag(({Live()}), 1);
+
gc(); return a;
+
}]], ({0}))
+
test_any_equal([[{
+
class Live {object o; void destroy() {}};
+
multiset l = set_weak_flag((<Live()>), 1);
+
gc(); return l;
+
}]], (<>))
+
test_any_equal([[{
+
class Live {object o; void destroy() {}};
+
mapping m = set_weak_flag(([0: Live()]), 1);
+
gc(); return m;
+
}]], ([]))
+
test_any_equal([[{
+
class Live {object o; void destroy() {}};
+
mapping m = set_weak_flag(([Live(): 0]), 1);
+
gc(); return m;
+
}]], ([]))
+
test_any_equal([[{
+
array a = set_weak_flag(({4711, 0x54325827a124*0x12348795482485425}), 1);
+
gc(); return a;
+
}]], ({4711, 0x54325827a124*0x12348795482485425}))
+
+
test_any([[{
+
class Dead {object o;};
+
object o = Dead(); o->o = Dead();
+
array a = set_weak_flag(({o}), 1);
+
gc(); o = 0; return gc() > 0;
+
}]], 1)
+
test_any([[{
+
class Dead {object o;};
+
class Live {object o; void destroy() {}};
+
object o = Live(); o->o = Dead();
+
array a = set_weak_flag(({o}), 1);
+
gc(); o = 0; return gc() > 0;
+
}]], 1)
+
test_any([[{
+
class Dead {object o;};
+
class Live {object o; void destroy() {}};
+
object o = Dead(); o->o = Live();
+
array a = set_weak_flag(({o}), 1);
+
gc(); o = 0; return gc() > 0;
+
}]], 1)
+
+
test_do([[{
+
int got_error = 0;
+
array(string) destruct_order;
+
add_constant ("destructing", lambda (string id) {destruct_order += ({id});});
+
add_constant ("my_error", lambda (string s, mixed... args) {
+
if (!got_error) werror ("\n");
+
werror (s, @args);
+
got_error = 1;
+
});
+
program Dead = compile_string (#"
+
string id;
+
void create (int i) {id = sprintf (\"dead[%d]\", i);}
+
mixed a = 1, b = 1; // Mustn't be zero at destruct time.
+
mixed x, y;
+
array v = set_weak_flag (({1}), 1); // Mustn't be zero at destruct time.
+
array w = set_weak_flag (({0, 0}), 1);
+
function(object:mixed) checkfn;
+
void check_live (mapping(object:int) checked) {
+
//werror (\"check_live %s\\n\", id);
+
checked[this_object()] = 1;
+
if (!a) my_error (id + \"->a got destructed too early.\\n\");
+
else if (!b) my_error (id + \"->b got destructed too early.\\n\");
+
else if (!v[0]) my_error (id + \"->v[0] got destructed too early.\\n\");
+
else if (functionp (checkfn) && !checkfn (this_object()))
+
my_error (id + \"->checkfn failed.\\n\");
+
else {
+
if (objectp (a) && !checked[a]) a->check_live (checked);
+
if (objectp (b) && !checked[b]) b->check_live (checked);
+
if (objectp (x) && !checked[x]) x->check_live (checked);
+
if (objectp (y) && !checked[y]) y->check_live (checked);
+
if (objectp (v[0]) && !checked[v[0] ]) v[0]->check_live (checked);
+
if (objectp (w[0]) && !checked[w[0] ]) w[0]->check_live (checked);
+
if (objectp (w[1]) && !checked[w[1] ]) w[1]->check_live (checked);
+
}
+
//werror (\"check_live %s done\\n\", id);
+
}
+
");
+
add_constant ("Dead", Dead);
+
program Live = compile_string (#"
+
inherit Dead;
+
void create (int i) {id = sprintf (\"live[%d]\", i);}
+
void destroy() {
+
destructing (id);
+
//werror (\"destroy %s\\n\", id);
+
check_live (([]));
+
}
+
");
+
add_constant ("Live", Live);
+
program Nested = compile_string (#"
+
inherit Live;
+
string id = \"nested[0]\";
+
void create() {}
+
void check_live_0 (mapping(object:int) checked) {check_live (checked);}
+
class Nested1
+
{
+
inherit Live;
+
string id = \"nested[1]\";
+
void create() {}
+
void check_live (mapping(object:int) checked) {
+
checked[this_object()] = 1;
+
if (catch (check_live_0 (checked)))
+
my_error (\"Parent for %s got destructed too early.\\n\", id);
+
else ::check_live (checked);
+
}
+
void check_live_1 (mapping(object:int) checked) {check_live (checked);}
+
class Nested2
+
{
+
inherit Live;
+
string id = \"nested[2]\";
+
void create() {}
+
void check_live (mapping(object:int) checked) {
+
checked[this_object()] = 1;
+
if (catch (check_live_1 (checked)))
+
my_error (\"Parent for %s got destructed too early.\\n\", id);
+
else ::check_live (checked);
+
}
+
}
+
class Nested3
+
{
+
inherit Live;
+
string id = \"nested[3]\";
+
void create() {}
+
void check_live (mapping(object:int) checked) {
+
checked[this_object()] = 1;
+
if (catch (check_live_1 (checked)))
+
my_error (\"Parent for %s got destructed too early.\\n\", id);
+
else ::check_live (checked);
+
}
+
}
+
}
+
");
+
add_constant ("destructing");
+
add_constant ("my_error");
+
add_constant ("Dead");
+
add_constant ("Live");
+
+
array(object) live, dead, nested;
+
array(array) destruct_order_tests = ({
+
({3, // Wanted number of live objects.
+
0, // Wanted number of dead objects.
+
0, // Wanted nested objects.
+
lambda() { // Function to connect them.
+
live[0]->x = live[1], live[0]->a = live[2];
+
live[1]->x = live[0];
+
}}),
+
({2, 2, 0, lambda() { // 1
+
live[0]->x = live[1], live[0]->a = dead[0];
+
live[1]->x = live[0];
+
dead[0]->a = dead[1];
+
dead[1]->a = dead[0];
+
}}),
+
({1, 2, 0, lambda() { // 2
+
live[0]->a = live[0], live[0]->b = dead[0];
+
dead[0]->a = dead[1];
+
dead[1]->a = dead[0];
+
}}),
+
({0, 3, 0, lambda() { // 3
+
dead[0]->a = dead[1];
+
dead[1]->a = dead[0];
+
dead[2]->a = dead[0], dead[2]->b = dead[2];
+
}}),
+
({3, 0, 0, lambda() { // 4
+
live[0]->a = live[0], live[0]->b = live[1];
+
live[1]->a = live[2];
+
}}),
+
({1, 2, 0, lambda() { // 5
+
live[0]->a = live[0], live[0]->b = dead[0];
+
dead[0]->a = dead[1];
+
}}),
+
({1, 2, 0, lambda() { // 6
+
live[0]->a = live[0], live[0]->b = dead[1];
+
dead[0]->a = dead[0], dead[0]->b = dead[1];
+
dead[1]->a = dead[1];
+
}}),
+
({2, 2, 0, lambda() { // 7
+
live[0]->a = live[0], live[0]->b = live[1];
+
dead[0]->a = dead[0];
+
dead[0]->b = live[1];
+
live[1]->a = dead[1];
+
dead[1]->a = dead[1];
+
}}),
+
({1, 3, 0, lambda() { // 8
+
live[0]->a = live[0], live[0]->b = dead[2];
+
dead[0]->a = dead[0];
+
dead[0]->b = dead[2];
+
dead[2]->a = dead[1];
+
dead[1]->a = dead[1];
+
}}),
+
({3, 1, 0, lambda() { // 9
+
live[0]->a = live[0], live[0]->b = live[1];
+
dead[0]->a = dead[0], dead[0]->b = live[1];
+
live[1]->a = live[2];
+
}}),
+
({1, 3, 0, lambda() { // 10
+
live[0]->a = live[0], live[0]->b = dead[1];
+
dead[0]->a = dead[0], dead[0]->b = dead[1];
+
dead[1]->a = dead[2];
+
}}),
+
({1, 3, 0, lambda() { // 11
+
live[0]->a = live[0], live[0]->b = dead[1];
+
dead[0]->a = dead[0], dead[0]->b = dead[1];
+
dead[1]->a = dead[1], dead[1]->b = dead[2];
+
dead[2]->a = dead[2];
+
}}),
+
({5, 0, 0, lambda() { // 12
+
live[0]->x = live[1];
+
live[1]->x = live[0], live[1]->a = live[2];
+
live[2]->x = live[3];
+
live[3]->x = live[2], live[3]->a = live[4];
+
live[4]->a = live[4];
+
}}),
+
({3, 0, 0, lambda() { // 13
+
live[0]->x = live[1], live[0]->y = live[2];
+
live[1]->x = live[2];
+
live[2]->x = live[0];
+
}}),
+
({2, 0, 0, lambda() { // 14
+
live[0]->a = live[1], live[0]->b = live[0];
+
live[1]->w[0] = live[0];
+
}}),
+
({2, 0, 0, lambda() { // 15
+
live[0]->a = live[0], live[0]->b = live[1];
+
live[1]->w[0] = live[0];
+
}}),
+
({2, 0, 0, lambda() { // 16
+
live[0]->a = live[0], live[0]->w[0] = live[1];
+
live[1]->x = live[0];
+
}}),
+
({3, 0, 0, lambda() { // 17
+
live[0]->a = live[0], live[0]->b = live[1];
+
live[1]->w[0] = live[2];
+
live[2]->a = live[2], live[2]->b = live[1];
+
}}),
+
({3, 0, 0, lambda() { // 18
+
live[0]->a = live[1], live[0]->x = live[2];
+
live[1]->w[0] = live[2];
+
live[2]->x = live[0];
+
}}),
+
({4, 0, 0, lambda() { // 19
+
live[0]->x = live[0], live[0]->a = live[1], live[0]->b = live[2];
+
live[1]->a = live[3];
+
live[2]->a = live[3];
+
live[3]->w[0] = live[0];
+
}}),
+
({3, 0, 0, lambda() { // 20
+
live[0]->x = live[1];
+
live[1]->x = live[0], live[1]->a = live[2];
+
live[2]->w[0] = live[1];
+
}}),
+
({4, 0, 0, lambda() { // 21
+
live[0]->w[0] = live[1], live[0]->a = live[3];
+
live[1]->w[0] = live[2];
+
live[2]->a = live[0], live[2]->b = live[3], live[2]->x = live[2];
+
live[3]->a = live[1];
+
}}),
+
({2, 1, 0, lambda() { // 22
+
live[0]->a = dead[0], live[0]->x = live[1];
+
live[1]->x = live[0];
+
dead[0]->w[0] = live[1];
+
}}),
+
({2, 1, 0, lambda() { // 23
+
live[0]->a = live[1], live[0]->b = dead[0];
+
live[1]->w[0] = dead[0];
+
dead[0]->x = live[0];
+
}}),
+
({3, 0, 0, lambda() { // 24
+
live[0]->x = live[0], live[0]->a = live[1], live[0]->b = live[2];
+
live[1]->w[0] = live[0], live[1]->w[1] = live[2];
+
live[2]->a = live[1];
+
}}),
+
({3, 0, 0, lambda() { // 25
+
live[0]->a = live[1];
+
live[1]->w[0] = live[2];
+
live[2]->x = live[2], live[2]->a = live[0], live[2]->b = live[1];
+
}}),
+
({3, 0, 0, lambda() { // 26
+
live[0]->w[0] = live[1], live[0]->a = live[2];
+
live[1]->x = live[1], live[1]->a = live[0], live[1]->b = live[2];
+
live[2]->w[0] = live[1];
+
}}),
+
({3, 0, 0, lambda() { // 27
+
live[0]->w[0] = live[1];
+
live[1]->x = live[1], live[1]->a = live[0], live[1]->b = live[2];
+
live[2]->a = live[0];
+
}}),
+
({3, 0, 0, lambda() { // 28
+
live[0]->a = live[0], live[0]->v[0] = live[1];
+
live[1]->a = live[1], live[1]->v[0] = live[2];
+
live[2]->a = live[2];
+
}}),
+
({2, 2, 0, lambda() { // 29
+
live[0]->x = live[1], live[0]->v[0] = dead[0];
+
live[1]->x = live[0];
+
dead[0]->a = dead[1];
+
dead[1]->a = dead[0];
+
}}),
+
({4, 0, 0, lambda() { // 30
+
live[0]->a = live[1], live[0]->b = live[2], live[0]->v[0] = live[3];
+
live[1]->w[0] = live[0];
+
live[2]->a = live[3];
+
live[3]->w[0] = live[2];
+
}}),
+
({2, 1, 0, lambda() { // 31
+
live[0]->a = dead[0];
+
dead[0]->a = live[0], dead[0]->b = live[1];
+
live[1]->a = live[1];
+
}}),
+
({2, 1, 0, lambda() { // 32
+
live[0]->a = live[0], live[0]->b = dead[0];
+
live[1]->a = dead[0];
+
dead[0]->a = live[1];
+
}}),
+
({2, 1, 0, lambda() { // 33
+
dead[0]->a = live[0];
+
live[0]->a = dead[0], live[0]->b = live[1];
+
live[1]->a = live[1];
+
}}),
+
({2, 1, 0, lambda() { // 34
+
live[0]->a = dead[0];
+
dead[0]->b = live[0], dead[0]->a = live[1];
+
live[1]->a = live[1];
+
}}),
+
({2, 1, 0, lambda() { // 35
+
live[0]->b = live[0], live[0]->a = dead[0];
+
live[1]->a = dead[0];
+
dead[0]->a = live[1];
+
}}),
+
({2, 1, 0, lambda() { // 36
+
dead[0]->a = live[0];
+
live[0]->b = dead[0], live[0]->a = live[1];
+
live[1]->a = live[1];
+
}}),
+
({3, 0, 0, lambda() { // 37
+
live[0]->a = live[0], live[0]->v[0] = live[1];
+
live[0]->checkfn = lambda (object o) {
+
return o->v[0]->w[0];
+
};
+
live[1]->w[0] = live[2];
+
live[2]->a = live[1], live[2]->b = live[2];
+
}}),
+
({4, 0, 0, lambda() { // 38
+
live[0]->x = live[1];
+
live[1]->x = live[2];
+
live[2]->x = live[0], live[2]->w[0] = live[3];
+
live[3]->a = live[1], live[3]->b = live[3];
+
}}),
+
({0, 2, 2, lambda() { // 39
+
dead[0]->x = dead[0], dead[0]->a = nested[0];
+
dead[1]->x = dead[1], dead[1]->a = nested[1];
+
nested[0]->x = nested[1];
+
}}),
+
({0, 2, 2, lambda() { // 40
+
dead[0]->x = dead[0], dead[0]->a = nested[0];
+
dead[1]->x = dead[1], dead[1]->a = nested[1];
+
nested[0]->w[0] = nested[1];
+
}}),
+
({3, 0, 3, lambda() { // 41
+
live[0]->x = live[0], live[0]->a = nested[0];
+
live[1]->x = live[1], live[1]->a = nested[2];
+
live[2]->x = live[2], live[2]->a = nested[1];
+
nested[0]->x = nested[2];
+
}}),
+
({4, 0, 4, lambda() { // 42
+
live[0]->x = live[0], live[0]->a = nested[0];
+
live[1]->x = live[1], live[1]->a = nested[1];
+
live[2]->x = live[2], live[2]->a = nested[2];
+
live[3]->x = live[3], live[3]->a = nested[3];
+
nested[0]->x = nested[3];
+
}}),
+
({3, 0, 2, lambda() { // 43
+
live[0]->x = live[0], live[0]->a = nested[0];
+
live[1]->x = live[1], live[1]->a = nested[1];
+
nested[0]->a = live[2];
+
live[2]->x = nested[1];
+
}}),
+
({3, 0, 3, lambda() { // 44
+
live[0]->x = live[0], live[0]->a = nested[0];
+
live[1]->x = live[1], live[1]->a = nested[2];
+
live[2]->x = live[2], live[2]->a = nested[1];
+
nested[0]->x = nested[2];
+
nested[1]->a = live[0];
+
}}),
+
// ({3, 0, 0, lambda() { // Not possible without weak refs directly in objects.
+
// live[0]->x = live[0], live[0]->v[0] = live[1];
+
// live[1]->x = live[1], live[1]->w[0] = live[2];
+
// live[2]->x = live[2], live[2]->a = live[0];
+
// }}),
+
});
+
+
int test_failed = 0;
+
for (int test = 0; test < sizeof (destruct_order_tests); test++) {
+
[int nlive, int ndead, int nnested, function(void:void) setup] =
+
destruct_order_tests[test];
+
int objs = nlive + ndead;
+
array(int) idx = indices (allocate (objs));
+
int n = 1;
+
for (int f = nlive + ndead; f > 1; f--) n *= f;
+
werror ("GC destruct order test %d, %d permutations \r", test, n);
+
while (n--) {
+
array(int) alloc_order = Array.permute (idx, n);
+
array(int) create_order = ({});
+
live = allocate (nlive);
+
dead = allocate (ndead);
+
if (nnested >= 1) {
+
// Creating these before the Dead and Live objects below assumes
+
// that the gc will start with the last created object first, so
+
// the order can be controlled with those objects.
+
nested = ({Nested()});
+
if (nnested >= 2) nested += ({nested[0]->Nested1()});
+
if (nnested >= 3) nested += ({nested[1]->Nested2()});
+
if (nnested >= 4) nested += ({nested[1]->Nested3()});
+
}
+
for (int i = 0; i < objs; i++) {
+
int p = alloc_order[i];
+
if (p < nlive) live[p] = Live (p), create_order += ({p});
+
else p -= nlive, dead[p] = Dead (p), create_order += ({-p - 1});
+
}
+
destruct_order = ({""}); // Using ({}) would alloc a new array in destructing().
+
setup();
+
live = dead = nested = 0;
+
int garbed = gc() + gc(); // Second gc to garb live object leftovers.
+
destruct_order = destruct_order[1..];
+
if (!got_error && (got_error = sizeof (destruct_order) != nlive + nnested))
+
werror ("\nGC should garb %d live objects, "
+
"but took %d.\n", nlive + nnested, sizeof (destruct_order));
+
if (!got_error && (got_error = garbed < 3 * (objs + nnested)))
+
werror ("\nGC should garb at least %d things, "
+
"but took only %d.\n", 3 * (objs + nnested), garbed);
+
if (got_error) {
+
werror ("Create order was: " +
+
map (create_order, lambda (int i) {
+
if (i < 0) return "dead[" + (-i - 1) + "]";
+
else return "live[" + i + "]";
+
}) * ", " + "\n"
+
"Destruct order was: " + destruct_order * ", " + "\n");
+
test_failed = 1;
+
got_error = 0;
+
error("");
+
break;
+
}
+
}
+
}
+
werror ("%60s\r", "");
+
if (test_failed) error ("GC destruct order test failed.\n");
+
}]])
]]) cond([[ sizeof( cpp("__AUTO_BIGNUM__")/"__AUTO_BIGNUM__" ) == 1 ]],