/* * TinyJS * * A single-file Javascript-alike engine * * Authored By Gordon Williams * * Copyright (C) 2009 Pur3 Ltd * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * This is a program to run all the tests in the tests folder... */ #include #include #include #include #include #include "TinyJS.h" #include "TinyJS_Functions.h" //#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); 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 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 return 0; }