formatting 90% done; encapsulated everything in the TinyJS namespace, and renamed...
[tinyjs-rewrite.git] / src / run_tests.cpp
blobaed7e57e8a3c4ef08ff8ae4b9672413197fc78bb
1 /*
2 * TinyJS
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
26 * SOFTWARE.
30 * This is a program to run all the tests in the tests folder...
33 #include "TinyJS.h"
34 #include "TinyJS_Functions.h"
35 #include "TinyJS_MathFunctions.h"
36 #include <assert.h>
37 #include <sys/stat.h>
38 #include <string>
39 #include <sstream>
40 #include <stdio.h>
42 #ifdef MTRACE
43 #include <mcheck.h>
44 #endif
46 //#define INSANE_MEMORY_DEBUG
48 #ifdef INSANE_MEMORY_DEBUG
49 // needs -rdynamic when compiling/linking
50 #include <execinfo.h>
51 #include <malloc.h>
52 #include <map>
53 #include <vector>
54 using namespace std;
56 void **get_stackframe() {
57 void **trace = (void**)malloc(sizeof(void*)*17);
58 int trace_size = 0;
60 for (int i=0;i<17;i++) trace[i]=(void*)0;
61 trace_size = backtrace(trace, 16);
62 return trace;
65 void print_stackframe(char *header, void **trace) {
66 char **messages = (char **)NULL;
67 int trace_size = 0;
69 trace_size = 0;
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]);
77 //free(messages);
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;
101 return result;
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 */
109 free (ptr);
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");
114 void *trace[16];
115 int trace_size = 0;
116 trace_size = backtrace(trace, 16);
117 backtrace_symbols_fd(trace, trace_size, STDERR_FILENO);*/
118 } else
119 malloced.erase(ptr);
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;
134 while (*trace) {
135 hash = (hash<<1) ^ (hash>>63) ^ (unsigned long)*trace;
136 trace++;
138 return hash;
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())
154 counts[hash] = 1;
155 else
156 counts[hash]++;
158 it++;
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));
165 countit++;
168 // sort
169 bool done = false;
170 while (!done) {
171 done = true;
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];
176 sorting[i+1] = t;
177 done = false;
183 for (int i=0;i<sorting.size();i++) {
184 long hash = sorting[i].second;
185 int count = sorting[i].first;
186 char header[256];
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);
196 struct stat results;
197 if (!stat(filename, &results) == 0) {
198 printf("Cannot stat file! '%s'\n", filename);
199 return false;
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 */
204 if( !file ) {
205 printf("Unable to open file! '%s'\n", filename);
206 return false;
208 char *buffer = new char[size+1];
209 long actualRead = fread(buffer,1,size,file);
210 buffer[actualRead]=0;
211 buffer[size]=0;
212 fclose(file);
214 Interpreter s;
215 registerFunctions(&s);
216 registerMathFunctions(&s);
217 s.getRoot()->addChild("result", new Variable("0",SCRIPTVAR_INTEGER));
218 try {
219 s.execute(buffer);
220 } catch (RuntimeError *e) {
221 printf("ERROR: %s\n", e->text.c_str());
223 bool pass = s.root->getParameter("result")->getBool();
225 if (pass)
226 printf("PASS\n");
227 else {
228 char fn[64];
229 sprintf(fn, "%s.fail.js", filename);
230 FILE *f = fopen(fn, "wt");
231 if (f) {
232 std::ostringstream symbols;
233 s.root->getJSON(symbols);
234 fprintf(f, "%s", symbols.str().c_str());
235 fclose(f);
238 printf("FAIL - symbols written to %s\n", fn);
241 delete[] buffer;
242 return pass;
245 int main(int argc, char **argv)
247 #ifdef MTRACE
248 mtrace();
249 #endif
250 #ifdef INSANE_MEMORY_DEBUG
251 memtracing_init();
252 #endif
253 printf("TinyJS test runner\n");
254 printf("USAGE:\n");
255 printf(" ./run_tests test.js : run just one test\n");
256 printf(" ./run_tests : run all tests\n");
257 if (argc==2) {
258 return !run_test(argv[1]);
261 int test_num = 1;
262 int count = 0;
263 int passed = 0;
265 while (test_num<1000) {
266 char fn[32];
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");
270 if (!f) break;
271 fclose(f);
273 if (run_test(fn))
274 passed++;
275 count++;
276 test_num++;
279 printf("Done. %d tests, %d pass, %d fail\n", count, passed, count-passed);
280 #ifdef INSANE_MEMORY_DEBUG
281 memtracing_kill();
282 #endif
284 #ifdef _DEBUG
285 #ifdef _WIN32
286 _CrtDumpMemoryLeaks();
287 #endif
288 #endif
289 #ifdef MTRACE
290 muntrace();
291 #endif
293 return 0;