/* * TinyJS * * A single-file Javascript-alike engine * * Authored By Gordon Williams * * Copyright (C) 2009 Pur3 Ltd * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* * This is a program to run all the tests in the tests folder... */ #include "TinyJS.h" #include "TinyJS_Functions.h" #include "TinyJS_MathFunctions.h" #include #include #include #include #include #ifdef MTRACE #include #endif //#define INSANE_MEMORY_DEBUG #ifdef INSANE_MEMORY_DEBUG // needs -rdynamic when compiling/linking #include #include #include #include using namespace std; void **get_stackframe() { void **trace = (void**)malloc(sizeof(void*)*17); int trace_size = 0; for (int i=0;i<17;i++) trace[i]=(void*)0; trace_size = backtrace(trace, 16); return trace; } void print_stackframe(char *header, void **trace) { char **messages = (char **)NULL; int trace_size = 0; trace_size = 0; while (trace[trace_size]) trace_size++; messages = backtrace_symbols(trace, trace_size); printf("%s\n", header); for (int i=0; i malloced; static void *my_malloc_hook(size_t size, const void *caller) { /* Restore all old hooks */ __malloc_hook = old_malloc_hook; __free_hook = old_free_hook; /* Call recursively */ void *result = malloc (size); /* we call malloc here, so protect it too. */ //printf ("malloc (%u) returns %p\n", (unsigned int) size, result); malloced[result] = get_stackframe(); /* Restore our own hooks */ __malloc_hook = my_malloc_hook; __free_hook = my_free_hook; return result; } static void my_free_hook(void *ptr, const void *caller) { /* Restore all old hooks */ __malloc_hook = old_malloc_hook; __free_hook = old_free_hook; /* Call recursively */ free (ptr); /* we call malloc here, so protect it too. */ //printf ("freed pointer %p\n", ptr); if (malloced.find(ptr) == malloced.end()) { /*fprintf(stderr, "INVALID FREE\n"); void *trace[16]; int trace_size = 0; trace_size = backtrace(trace, 16); backtrace_symbols_fd(trace, trace_size, STDERR_FILENO);*/ } else malloced.erase(ptr); /* Restore our own hooks */ __malloc_hook = my_malloc_hook; __free_hook = my_free_hook; } void memtracing_init() { old_malloc_hook = __malloc_hook; old_free_hook = __free_hook; __malloc_hook = my_malloc_hook; __free_hook = my_free_hook; } long gethash(void **trace) { unsigned long hash = 0; while (*trace) { hash = (hash<<1) ^ (hash>>63) ^ (unsigned long)*trace; trace++; } return hash; } void memtracing_kill() { /* Restore all old hooks */ __malloc_hook = old_malloc_hook; __free_hook = old_free_hook; map hashToReal; map counts; map::iterator it = malloced.begin(); while (it!=malloced.end()) { long hash = gethash(it->second); hashToReal[hash] = it->second; if (counts.find(hash) == counts.end()) counts[hash] = 1; else counts[hash]++; it++; } vector > sorting; map::iterator countit = counts.begin(); while (countit!=counts.end()) { sorting.push_back(pair(countit->second, countit->first)); countit++; } // sort bool done = false; while (!done) { done = true; for (int i=0;i t = sorting[i]; sorting[i] = sorting[i+1]; sorting[i+1] = t; done = false; } } } for (int i=0;i the size we read */ if( !file ) { printf("Unable to open file! '%s'\n", filename); return false; } char *buffer = new char[size+1]; long actualRead = fread(buffer,1,size,file); buffer[actualRead]=0; buffer[size]=0; fclose(file); CTinyJS s; registerFunctions(&s); registerMathFunctions(&s); s.root->addChild("result", new CScriptVar("0",SCRIPTVAR_INTEGER)); try { s.execute(buffer); } catch (CScriptException *e) { printf("ERROR: %s\n", e->text.c_str()); } bool pass = s.root->getParameter("result")->getBool(); if (pass) printf("PASS\n"); else { char fn[64]; sprintf(fn, "%s.fail.js", filename); FILE *f = fopen(fn, "wt"); if (f) { std::ostringstream symbols; s.root->getJSON(symbols); fprintf(f, "%s", symbols.str().c_str()); fclose(f); } printf("FAIL - symbols written to %s\n", fn); } delete[] buffer; return pass; } int main(int argc, char **argv) { #ifdef MTRACE mtrace(); #endif #ifdef INSANE_MEMORY_DEBUG memtracing_init(); #endif printf("TinyJS test runner\n"); printf("USAGE:\n"); printf(" ./run_tests test.js : run just one test\n"); printf(" ./run_tests : run all tests\n"); if (argc==2) { return !run_test(argv[1]); } int test_num = 1; int count = 0; int passed = 0; while (test_num<1000) { char fn[32]; sprintf(fn, "tests/test%03d.js", test_num); // check if the file exists - if not, assume we're at the end of our tests FILE *f = fopen(fn,"r"); if (!f) break; fclose(f); if (run_test(fn)) passed++; count++; test_num++; } printf("Done. %d tests, %d pass, %d fail\n", count, passed, count-passed); #ifdef INSANE_MEMORY_DEBUG memtracing_kill(); #endif #ifdef _DEBUG #ifdef _WIN32 _CrtDumpMemoryLeaks(); #endif #endif #ifdef MTRACE muntrace(); #endif return 0; }