4 * A single-file Javascript-alike engine
6 * Authored By Gordon Williams <gw@pur3.co.uk>
8 * Copyright (C) 2009 Pur3 Ltd
10 * Permission is hereby granted, free of charge, to any person obtaining a copy of
11 * this software and associated documentation files (the "Software"), to deal in
12 * the Software without restriction, including without limitation the rights to
13 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
14 * of the Software, and to permit persons to whom the Software is furnished to do
15 * so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included in all
18 * copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * This is a program to run all the tests in the tests folder...
34 #include "TinyJS_Functions.h"
35 #include "TinyJS_MathFunctions.h"
46 //#define INSANE_MEMORY_DEBUG
48 #ifdef INSANE_MEMORY_DEBUG
49 // needs -rdynamic when compiling/linking
56 void **get_stackframe() {
57 void **trace
= (void**)malloc(sizeof(void*)*17);
60 for (int i
=0;i
<17;i
++) trace
[i
]=(void*)0;
61 trace_size
= backtrace(trace
, 16);
65 void print_stackframe(char *header
, void **trace
) {
66 char **messages
= (char **)NULL
;
70 while (trace
[trace_size
]) trace_size
++;
71 messages
= backtrace_symbols(trace
, trace_size
);
73 printf("%s\n", header
);
74 for (int i
=0; i
<trace_size
; ++i
) {
75 printf("%s\n", messages
[i
]);
80 /* Prototypes for our hooks. */
81 static void *my_malloc_hook (size_t, const void *);
82 static void my_free_hook (void*, const void *);
83 static void *(*old_malloc_hook
) (size_t, const void *);
84 static void (*old_free_hook
) (void*, const void *);
86 map
<void *, void **> malloced
;
88 static void *my_malloc_hook(size_t size
, const void *caller
) {
89 /* Restore all old hooks */
90 __malloc_hook
= old_malloc_hook
;
91 __free_hook
= old_free_hook
;
92 /* Call recursively */
93 void *result
= malloc (size
);
94 /* we call malloc here, so protect it too. */
95 //printf ("malloc (%u) returns %p\n", (unsigned int) size, result);
96 malloced
[result
] = get_stackframe();
98 /* Restore our own hooks */
99 __malloc_hook
= my_malloc_hook
;
100 __free_hook
= my_free_hook
;
104 static void my_free_hook(void *ptr
, const void *caller
) {
105 /* Restore all old hooks */
106 __malloc_hook
= old_malloc_hook
;
107 __free_hook
= old_free_hook
;
108 /* Call recursively */
110 /* we call malloc here, so protect it too. */
111 //printf ("freed pointer %p\n", ptr);
112 if (malloced
.find(ptr
) == malloced
.end()) {
113 /*fprintf(stderr, "INVALID FREE\n");
116 trace_size = backtrace(trace, 16);
117 backtrace_symbols_fd(trace, trace_size, STDERR_FILENO);*/
120 /* Restore our own hooks */
121 __malloc_hook
= my_malloc_hook
;
122 __free_hook
= my_free_hook
;
125 void memtracing_init() {
126 old_malloc_hook
= __malloc_hook
;
127 old_free_hook
= __free_hook
;
128 __malloc_hook
= my_malloc_hook
;
129 __free_hook
= my_free_hook
;
132 long gethash(void **trace
) {
133 unsigned long hash
= 0;
135 hash
= (hash
<<1) ^ (hash
>>63) ^ (unsigned long)*trace
;
141 void memtracing_kill() {
142 /* Restore all old hooks */
143 __malloc_hook
= old_malloc_hook
;
144 __free_hook
= old_free_hook
;
146 map
<long, void**> hashToReal
;
147 map
<long, int> counts
;
148 map
<void *, void **>::iterator it
= malloced
.begin();
149 while (it
!=malloced
.end()) {
150 long hash
= gethash(it
->second
);
151 hashToReal
[hash
] = it
->second
;
153 if (counts
.find(hash
) == counts
.end())
161 vector
<pair
<int, long> > sorting
;
162 map
<long, int>::iterator countit
= counts
.begin();
163 while (countit
!=counts
.end()) {
164 sorting
.push_back(pair
<int, long>(countit
->second
, countit
->first
));
172 for (int i
=0;i
<sorting
.size()-1;i
++) {
173 if (sorting
[i
].first
< sorting
[i
+1].first
) {
174 pair
<int, long> t
= sorting
[i
];
175 sorting
[i
] = sorting
[i
+1];
183 for (int i
=0;i
<sorting
.size();i
++) {
184 long hash
= sorting
[i
].second
;
185 int count
= sorting
[i
].first
;
187 sprintf(header
, "--------------------------- LEAKED %d", count
);
188 print_stackframe(header
, hashToReal
[hash
]);
191 #endif // INSANE_MEMORY_DEBUG
194 bool run_test(const char *filename
) {
195 printf("TEST %s ", filename
);
197 if (!stat(filename
, &results
) == 0) {
198 printf("Cannot stat file! '%s'\n", filename
);
201 int size
= results
.st_size
;
202 FILE *file
= fopen( filename
, "rb" );
203 /* if we open as text, the number of bytes read may be > the size we read */
205 printf("Unable to open file! '%s'\n", filename
);
208 char *buffer
= new char[size
+1];
209 long actualRead
= fread(buffer
,1,size
,file
);
210 buffer
[actualRead
]=0;
215 registerFunctions(&s
);
216 registerMathFunctions(&s
);
217 s
.getRoot()->addChild("result", new Variable("0",SCRIPTVAR_INTEGER
));
220 } catch (RuntimeError
*e
) {
221 printf("ERROR: %s\n", e
->text
.c_str());
223 bool pass
= s
.root
->getParameter("result")->getBool();
229 sprintf(fn
, "%s.fail.js", filename
);
230 FILE *f
= fopen(fn
, "wt");
232 std::ostringstream symbols
;
233 s
.root
->getJSON(symbols
);
234 fprintf(f
, "%s", symbols
.str().c_str());
238 printf("FAIL - symbols written to %s\n", fn
);
245 int main(int argc
, char **argv
)
250 #ifdef INSANE_MEMORY_DEBUG
253 printf("TinyJS test runner\n");
255 printf(" ./run_tests test.js : run just one test\n");
256 printf(" ./run_tests : run all tests\n");
258 return !run_test(argv
[1]);
265 while (test_num
<1000) {
267 sprintf(fn
, "tests/test%03d.js", test_num
);
268 // check if the file exists - if not, assume we're at the end of our tests
269 FILE *f
= fopen(fn
,"r");
279 printf("Done. %d tests, %d pass, %d fail\n", count
, passed
, count
-passed
);
280 #ifdef INSANE_MEMORY_DEBUG
286 _CrtDumpMemoryLeaks();