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