formatting 90% done; encapsulated everything in the TinyJS namespace, and renamed...
[tinyjs-rewrite.git] / .svn / pristine / 0c / 0cb994438d5e82bac26e515e81375ad80ee8a9e2.svn-base
blobd1c7f05963326b42d65f06f7f910dd85b64c48a6
1 /*\r
2  * TinyJS\r
3  *\r
4  * A single-file Javascript-alike engine\r
5  *\r
6  * Authored By Gordon Williams <gw@pur3.co.uk>\r
7  *\r
8  * Copyright (C) 2009 Pur3 Ltd\r
9  *\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
26  * SOFTWARE.\r
27  */\r
29 /*\r
30  * This is a program to run all the tests in the tests folder...\r
31  */\r
33 #include "TinyJS.h"\r
34 #include "TinyJS_Functions.h"\r
35 #include "TinyJS_MathFunctions.h"\r
36 #include <assert.h>\r
37 #include <sys/stat.h>\r
38 #include <string>\r
39 #include <sstream>\r
40 #include <stdio.h>\r
42 #ifdef MTRACE\r
43   #include <mcheck.h>\r
44 #endif\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
51 #include <malloc.h>\r
52 #include <map>\r
53 #include <vector>\r
54 using namespace std;\r
56 void **get_stackframe() {\r
57   void **trace = (void**)malloc(sizeof(void*)*17);\r
58   int trace_size = 0;\r
60   for (int i=0;i<17;i++) trace[i]=(void*)0;\r
61   trace_size = backtrace(trace, 16);\r
62   return trace;\r
63 }\r
65 void print_stackframe(char *header, void **trace) {\r
66   char **messages = (char **)NULL;\r
67   int trace_size = 0;\r
69   trace_size = 0;\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
76   }\r
77   //free(messages);\r
78 }\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
101     return result;\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
109     free (ptr);\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
114       void *trace[16];\r
115       int trace_size = 0;\r
116       trace_size = backtrace(trace, 16);\r
117       backtrace_symbols_fd(trace, trace_size, STDERR_FILENO);*/\r
118     } else\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
134     while (*trace) {\r
135       hash = (hash<<1) ^ (hash>>63) ^ (unsigned long)*trace;\r
136       trace++;\r
137     }\r
138     return hash;\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
154         counts[hash] = 1;\r
155       else\r
156         counts[hash]++;\r
158       it++;\r
159     }\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
165       countit++;\r
166     }\r
168     // sort\r
169     bool done = false;\r
170     while (!done) {\r
171       done = true;\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
176           sorting[i+1] = t;\r
177           done = false;\r
178         }\r
179       }\r
180     }\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
186       char header[256];\r
187       sprintf(header, "--------------------------- LEAKED %d", count);\r
188       print_stackframe(header, hashToReal[hash]);\r
189     }\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
199     return false;\r
200   }\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
204   if( !file ) {\r
205      printf("Unable to open file! '%s'\n", filename);\r
206      return false;\r
207   }\r
208   char *buffer = new char[size+1];\r
209   long actualRead = fread(buffer,1,size,file);\r
210   buffer[actualRead]=0;\r
211   buffer[size]=0;\r
212   fclose(file);\r
214   CTinyJS s;\r
215   registerFunctions(&s);\r
216   registerMathFunctions(&s);\r
217   s.root->addChild("result", new CScriptVar("0",SCRIPTVAR_INTEGER));\r
218   try {\r
219     s.execute(buffer);\r
220   } catch (CScriptException *e) {\r
221     printf("ERROR: %s\n", e->text.c_str());\r
222   }\r
223   bool pass = s.root->getParameter("result")->getBool();\r
225   if (pass)\r
226     printf("PASS\n");\r
227   else {\r
228     char fn[64];\r
229     sprintf(fn, "%s.fail.js", filename);\r
230     FILE *f = fopen(fn, "wt");\r
231     if (f) {\r
232       std::ostringstream symbols;\r
233       s.root->getJSON(symbols);\r
234       fprintf(f, "%s", symbols.str().c_str());\r
235       fclose(f);\r
236     }\r
238     printf("FAIL - symbols written to %s\n", fn);\r
239   }\r
241   delete[] buffer;\r
242   return pass;\r
245 int main(int argc, char **argv)\r
247 #ifdef MTRACE\r
248   mtrace();\r
249 #endif\r
250 #ifdef INSANE_MEMORY_DEBUG\r
251     memtracing_init();\r
252 #endif\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
257   if (argc==2) {\r
258     return !run_test(argv[1]);\r
259   }\r
261   int test_num = 1;\r
262   int count = 0;\r
263   int passed = 0;\r
265   while (test_num<1000) {\r
266     char fn[32];\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
270     if (!f) break;\r
271     fclose(f);\r
273     if (run_test(fn))\r
274       passed++;\r
275     count++;\r
276     test_num++;\r
277   }\r
279   printf("Done. %d tests, %d pass, %d fail\n", count, passed, count-passed);\r
280 #ifdef INSANE_MEMORY_DEBUG\r
281     memtracing_kill();\r
282 #endif\r
284 #ifdef _DEBUG\r
285  #ifdef _WIN32\r
286   _CrtDumpMemoryLeaks();\r
287  #endif\r
288 #endif\r
289 #ifdef MTRACE\r
290   muntrace();\r
291 #endif\r
293   return 0;\r