diff options
-rw-r--r-- | tests/CMakeLists.txt | 60 | ||||
-rw-r--r-- | tests/OffscreenContext.h | 2 | ||||
-rw-r--r-- | tests/OffscreenContext.mm | 10 | ||||
-rw-r--r-- | tests/OffscreenContextGLX.cc (renamed from tests/OffscreenContext.cc) | 63 | ||||
-rw-r--r-- | tests/OffscreenContextWGL.cc | 45 | ||||
-rw-r--r-- | tests/OffscreenView.cc | 35 | ||||
-rw-r--r-- | tests/OffscreenView.h | 2 | ||||
-rw-r--r-- | tests/cgalpngtest.cc | 3 | ||||
-rw-r--r-- | tests/csgtestcore.cc | 97 | ||||
-rw-r--r-- | tests/fbo.cc | 21 | ||||
-rw-r--r-- | tests/system-gl.cc | 38 | ||||
-rw-r--r-- | tests/system-gl.h | 3 | ||||
-rwxr-xr-x | tests/test_cmdline_tool.py | 9 | ||||
-rwxr-xr-x | tests/test_pretty_print.py | 321 |
14 files changed, 630 insertions, 79 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 221500a..5e93680 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -75,24 +75,26 @@ if (NOT $ENV{MACOSX_DEPLOY_DIR} STREQUAL "") set(BOOST_ROOT "$ENV{MACOSX_DEPLOY_DIR}") endif() -if(BOOST_ROOT) - #set(Boost_DEBUG TRUE) - set(Boost_NO_SYSTEM_PATHS TRUE) - set(Boost_ADDITIONAL_VERSIONS "1.47.0") - find_package( Boost 1.35.0 COMPONENTS thread program_options ) - if(Boost_FOUND) - message(STATUS "Boost includes found: " ${Boost_INCLUDE_DIRS}) - message(STATUS "Boost libraries found:") - foreach(boostlib ${Boost_LIBRARIES}) - message(STATUS " " ${boostlib}) - endforeach() - include_directories(${Boost_INCLUDE_DIRS}) - else() - message(STATUS "BOOST_ROOT:" ${BOOST_ROOT}) - message(FATAL_ERROR "BOOST_ROOT specified but no boost found") - endif() +if (WIN32) + set(Boost_USE_STATIC_LIBS TRUE) + set(BOOST_STATIC TRUE) + set(BOOST_THREAD_USE_LIB TRUE) +endif() + +#set(Boost_DEBUG TRUE) +set(Boost_NO_SYSTEM_PATHS TRUE) +set(Boost_ADDITIONAL_VERSIONS "1.47.0" "1.46.0") +find_package( Boost 1.35.0 COMPONENTS thread program_options ) +if(Boost_FOUND) + message(STATUS "Boost includes found: " ${Boost_INCLUDE_DIRS}) + message(STATUS "Boost libraries found:") + foreach(boostlib ${Boost_LIBRARIES}) + message(STATUS " " ${boostlib}) + endforeach() + include_directories(${Boost_INCLUDE_DIRS}) else() - message(STATUS "BOOST_ROOT unset. Assuming it will be found automatically.") + message(STATUS "BOOST_ROOT: ${BOOST_ROOT}") + message(FATAL_ERROR "Boost not found.") endif() # Mac OS X @@ -258,13 +260,13 @@ set(COMMON_SOURCES # if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") message(STATUS "Offscreen OpenGL Context - using Apple CGL") - set(OFFSCREEN_CTX_SOURCE "OffscreenContext.mm") + set(OFFSCREEN_CTX_SOURCE "OffscreenContext.mm" CACHE TYPE STRING) elseif(UNIX) message(STATUS "Offscreen OpenGL Context - using Unix GLX") - set(OFFSCREEN_CTX_SOURCE "OffscreenContext.cc") + set(OFFSCREEN_CTX_SOURCE "OffscreenContextGLX.cc" CACHE TYPE STRING) elseif(WIN32) message(STATUS "Offscreen OpenGL Context - using Microsoft WGL") - set(OFFSCREEN_CTX_SOURCE "OffscreenContextWGL.cc") + set(OFFSCREEN_CTX_SOURCE "OffscreenContextWGL.cc" CACHE TYPE STRING) endif() set(OFFSCREEN_SOURCES @@ -360,6 +362,24 @@ endfunction() enable_testing() +# set up custom pretty printing of results + +set(INFOCMD "execute_process(COMMAND ${CMAKE_CURRENT_BINARY_DIR}/opencsgtest --info OUTPUT_FILE sysinfo.txt)") +set(PRETTYCMD "\"${PYTHON_EXECUTABLE} test_pretty_print.py\"") +set(CTEST_CUSTOM_FILE ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake) +set(CTEST_CUSTOM_TXT "\n + message(\"running 'opencsgtest --info' to generate sysinfo.txt\")\n + ${INFOCMD}\n + # set(CTEST_CUSTOM_POST_TEST ${PRETTYCMD})\n # doesn't work. log is written + # after all tests run. +") +file(WRITE ${CTEST_CUSTOM_FILE} ${CTEST_CUSTOM_TXT}) + +foreach(FILE test_pretty_print.py) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${FILE} + ${CMAKE_CURRENT_BINARY_DIR}/${FILE} COPYONLY) +endforeach() + # Find all scad files file(GLOB MINIMAL_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/minimal/*.scad) file(GLOB FEATURES_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/*.scad) diff --git a/tests/OffscreenContext.h b/tests/OffscreenContext.h index a079c3f..6eebcba 100644 --- a/tests/OffscreenContext.h +++ b/tests/OffscreenContext.h @@ -2,10 +2,12 @@ #define OFFSCREENCONTEXT_H_ #include <iostream> // for error output +#include <string> struct OffscreenContext *create_offscreen_context(int w, int h); void bind_offscreen_context(OffscreenContext *ctx); bool teardown_offscreen_context(OffscreenContext *ctx); bool save_framebuffer(OffscreenContext *ctx, const char *filename); +std::string offscreen_context_getinfo(OffscreenContext *ctx); #endif diff --git a/tests/OffscreenContext.mm b/tests/OffscreenContext.mm index 140516f..5a6a8ec 100644 --- a/tests/OffscreenContext.mm +++ b/tests/OffscreenContext.mm @@ -16,6 +16,15 @@ struct OffscreenContext fbo_t *fbo; }; +string offscreen_context_getinfo(OffscreenContext *ctx) +{ + stringstream out; + out << "GL context creator: Cocoa / CGL\n" + << "PNG generator: Core Foundation\n" + << "OS info: Mac OSX\n" + << "Machine: Apple(TM) Mac(TM)\n"; + return out.str(); +} OffscreenContext *create_offscreen_context(int w, int h) { @@ -94,6 +103,7 @@ bool teardown_offscreen_context(OffscreenContext *ctx) */ bool save_framebuffer(OffscreenContext *ctx, const char *filename) { + if (!ctx || !filename) return false; // Read pixels from OpenGL int samplesPerPixel = 4; // R, G, B and A int rowBytes = samplesPerPixel * ctx->width; diff --git a/tests/OffscreenContext.cc b/tests/OffscreenContextGLX.cc index 839eea9..e607593 100644 --- a/tests/OffscreenContext.cc +++ b/tests/OffscreenContextGLX.cc @@ -44,6 +44,11 @@ See Also #include <GL/gl.h> #include <GL/glx.h> +#include <assert.h> +#include <sstream> + +#include <sys/utsname.h> // for uname + using namespace std; struct OffscreenContext @@ -66,6 +71,42 @@ void offscreen_context_init(OffscreenContext &ctx, int width, int height) ctx.fbo = NULL; } +string get_os_info() +{ + struct utsname u; + stringstream out; + + if (uname(&u) < 0) + out << "OS info: unknown, uname() error\n"; + else { + out << "OS info: " + << u.sysname << " " + << u.release << " " + << u.version << "\n"; + out << "Machine: " << u.machine; + } + return out.str(); +} + +string offscreen_context_getinfo(OffscreenContext *ctx) +{ + assert(ctx); + + if (!ctx->xdisplay) + return string("No GL Context initialized. No information to report\n"); + + int major, minor; + glXQueryVersion(ctx->xdisplay, &major, &minor); + + stringstream out; + out << "GL context creator: GLX\n" + << "PNG generator: lodepng\n" + << "GLX version: " << major << "." << minor << "\n" + << get_os_info(); + + return out.str(); +} + static XErrorHandler original_xlib_handler = (XErrorHandler) NULL; static bool XCreateWindow_failed = false; static int XCreateWindow_error(Display *dpy, XErrorEvent *event) @@ -94,11 +135,15 @@ bool create_glx_dummy_window(OffscreenContext &ctx) */ int attributes[] = { - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT, //support all 3, for OpenCSG GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GLX_DEPTH_SIZE, 24, // depth-stencil for OpenCSG + GLX_STENCIL_SIZE, 8, + GLX_DOUBLEBUFFER, True, None }; @@ -123,8 +168,9 @@ bool create_glx_dummy_window(OffscreenContext &ctx) Window root = DefaultRootWindow( dpy ); XSetWindowAttributes xwin_attr; - int width = 42; - int height = 42; + int width = ctx.width; + int height = ctx.height; + xwin_attr.background_pixmap = None; xwin_attr.background_pixel = 0; xwin_attr.border_pixel = 0; xwin_attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone); @@ -137,7 +183,6 @@ bool create_glx_dummy_window(OffscreenContext &ctx) // Window xWin = XCreateSimpleWindow( dpy, DefaultRootWindow(dpy), 0,0,42,42, 0,0,0 ); - XSync( dpy, false ); if ( XCreateWindow_failed ) { XFree( visinfo ); @@ -227,7 +272,6 @@ OffscreenContext *create_offscreen_context(int w, int h) cerr << "Unable to init GLEW: " << glewGetErrorString(err) << endl; return NULL; } - glew_dump(); ctx->fbo = fbo_new(); if (!fbo_init(ctx->fbo, w, h)) { @@ -256,6 +300,7 @@ bool teardown_offscreen_context(OffscreenContext *ctx) */ bool save_framebuffer(OffscreenContext *ctx, const char *filename) { + glXSwapBuffers(ctx->xdisplay, ctx->xwindow); if (!ctx || !filename) return false; int samplesPerPixel = 4; // R, G, B and A GLubyte pixels[ctx->width * ctx->height * samplesPerPixel]; @@ -265,7 +310,7 @@ bool save_framebuffer(OffscreenContext *ctx, const char *filename) int rowBytes = samplesPerPixel * ctx->width; unsigned char *flippedBuffer = (unsigned char *)malloc(rowBytes * ctx->height); if (!flippedBuffer) { - std::cerr << "Unable to allocate flipped buffer for corrected image."; + cerr << "Unable to allocate flipped buffer for corrected image."; return 1; } flip_image(pixels, flippedBuffer, samplesPerPixel, ctx->width, ctx->height); diff --git a/tests/OffscreenContextWGL.cc b/tests/OffscreenContextWGL.cc index 3b966e2..ba12a4f 100644 --- a/tests/OffscreenContextWGL.cc +++ b/tests/OffscreenContextWGL.cc @@ -22,6 +22,10 @@ For more info: #include <GL/gl.h> // must be included after glew.h +#include <map> +#include <string> +#include <sstream> + using namespace std; struct OffscreenContext @@ -44,6 +48,45 @@ void offscreen_context_init(OffscreenContext &ctx, int width, int height) ctx.fbo = NULL; } +string get_os_info() +{ + OSVERSIONINFO osvi; + + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + SYSTEM_INFO si; + GetSystemInfo(&si); + map<WORD,const char*> archs; + archs[PROCESSOR_ARCHITECTURE_AMD64] = "amd64"; + archs[PROCESSOR_ARCHITECTURE_IA64] = "itanium"; + archs[PROCESSOR_ARCHITECTURE_INTEL] = "x86"; + archs[PROCESSOR_ARCHITECTURE_UNKNOWN] = "unknown"; + + stringstream out; + out << "OS info: " + << "Microsoft(TM) Windows(TM) " << osvi.dwMajorVersion << " " + << osvi.dwMinorVersion << " " << osvi.dwBuildNumber << " " + << osvi.szCSDVersion; + if (archs.find(si.wProcessorArchitecture) != archs.end()) + out << " " << archs[si.wProcessorArchitecture]; + out << "\n"; + + out << "Machine: " << si.dwProcessorType; + + return out.str(); +} + +string offscreen_context_getinfo(OffscreenContext *ctx) +{ + stringstream out; + out << "GL context creator: WGL\n" + out << "PNG generator: lodepng\n" + << get_windows_info(); + return out.str(); +} + LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { return DefWindowProc( hwnd, message, wparam, lparam ); @@ -142,7 +185,7 @@ OffscreenContext *create_offscreen_context(int w, int h) cerr << "Unable to init GLEW: " << glewGetErrorString(err) << "\n"; return NULL; } - glew_dump(); + //cerr << glew_dump(0); ctx->fbo = fbo_new(); if (!fbo_init(ctx->fbo, w, h)) { diff --git a/tests/OffscreenView.cc b/tests/OffscreenView.cc index 46951c1..9c8964c 100644 --- a/tests/OffscreenView.cc +++ b/tests/OffscreenView.cc @@ -1,11 +1,13 @@ #include <GL/glew.h> #include "OffscreenView.h" +#include "system-gl.h" #include <opencsg.h> #include "renderer.h" #include <math.h> #include <stdio.h> #include <string.h> #include <cstdlib> +#include <sstream> #define FAR_FAR_AWAY 100000.0 @@ -17,19 +19,6 @@ OffscreenView::OffscreenView(size_t width, size_t height) this->ctx = create_offscreen_context(width, height); if ( this->ctx == NULL ) throw -1; -#ifdef DEBUG - GLint rbits, gbits, bbits, abits, dbits, sbits; - glGetIntegerv(GL_RED_BITS, &rbits); - glGetIntegerv(GL_GREEN_BITS, &gbits); - glGetIntegerv(GL_BLUE_BITS, &bbits); - glGetIntegerv(GL_ALPHA_BITS, &abits); - glGetIntegerv(GL_DEPTH_BITS, &dbits); - glGetIntegerv(GL_STENCIL_BITS, &sbits); - - fprintf(stderr, "FBO: RGBA(%d%d%d%d), depth(%d), stencil(%d)\n", - rbits, gbits, bbits, abits, dbits, sbits); -#endif - initializeGL(); resizeGL(width, height); } @@ -249,6 +238,26 @@ bool OffscreenView::save(const char *filename) return save_framebuffer(this->ctx, filename); } +std::string OffscreenView::getInfo() +{ + std::stringstream out; + GLint rbits, gbits, bbits, abits, dbits, sbits; + glGetIntegerv(GL_RED_BITS, &rbits); + glGetIntegerv(GL_GREEN_BITS, &gbits); + glGetIntegerv(GL_BLUE_BITS, &bbits); + glGetIntegerv(GL_ALPHA_BITS, &abits); + glGetIntegerv(GL_DEPTH_BITS, &dbits); + glGetIntegerv(GL_STENCIL_BITS, &sbits); + + out << glew_dump(false) + << "FBO: RGBA(" << rbits << gbits << bbits << abits + << "), depth(" << dbits + << "), stencil(" << sbits << ")\n" + << offscreen_context_getinfo(this->ctx); + + return out.str(); +} + void OffscreenView::setCamera(const Eigen::Vector3d &pos, const Eigen::Vector3d ¢er) { this->camera_eye = pos; diff --git a/tests/OffscreenView.h b/tests/OffscreenView.h index e3c8579..2e35921 100644 --- a/tests/OffscreenView.h +++ b/tests/OffscreenView.h @@ -4,6 +4,7 @@ #include "OffscreenContext.h" #include <Eigen/Core> #include <Eigen/Geometry> +#include <string> #ifndef _MSC_VER #include <stdint.h> #endif @@ -22,6 +23,7 @@ public: void setupOrtho(bool offset=false); void paintGL(); bool save(const char *filename); + std::string getInfo(); GLint shaderinfo[11]; OffscreenContext *ctx; diff --git a/tests/cgalpngtest.cc b/tests/cgalpngtest.cc index bfa92da..cc747fb 100644 --- a/tests/cgalpngtest.cc +++ b/tests/cgalpngtest.cc @@ -190,16 +190,19 @@ int main(int argc, char **argv) BoundingBox bbox; if (cgalRenderer.polyhedron) { + std::cout << "polyhedron\n" ; CGAL::Bbox_3 cgalbbox = cgalRenderer.polyhedron->bbox(); bbox = BoundingBox(Vector3d(cgalbbox.xmin(), cgalbbox.ymin(), cgalbbox.zmin()), Vector3d(cgalbbox.xmax(), cgalbbox.ymax(), cgalbbox.zmax())); } else if (cgalRenderer.polyset) { + std::cout << "polyset\n" ; bbox = cgalRenderer.polyset->getBoundingBox(); } Vector3d center = getBoundingCenter(bbox); double radius = getBoundingRadius(bbox); + std::cout << "radius: " << radius << "\n"; Vector3d cameradir(1, 1, -0.5); Vector3d camerapos = center - radius*2*cameradir; diff --git a/tests/csgtestcore.cc b/tests/csgtestcore.cc index 034084c..a3d5097 100644 --- a/tests/csgtestcore.cc +++ b/tests/csgtestcore.cc @@ -25,8 +25,15 @@ #include <QDir> #include <QSet> #include <QTimer> + #include <sstream> +#include <vector> + +#include <boost/program_options.hpp> +namespace po = boost::program_options; +using std::string; +using std::vector; using std::cerr; using std::cout; @@ -41,9 +48,9 @@ public: CsgInfo(); CSGTerm *root_norm_term; // Normalized CSG products class CSGChain *root_chain; - std::vector<CSGTerm*> highlight_terms; + vector<CSGTerm*> highlight_terms; CSGChain *highlights_chain; - std::vector<CSGTerm*> background_terms; + vector<CSGTerm*> background_terms; CSGChain *background_chain; OffscreenView *glview; }; @@ -51,9 +58,9 @@ public: CsgInfo::CsgInfo() { root_norm_term = NULL; root_chain = NULL; - highlight_terms = std::vector<CSGTerm*>(); + highlight_terms = vector<CSGTerm*>(); highlights_chain = NULL; - background_terms = std::vector<CSGTerm*>(); + background_terms = vector<CSGTerm*>(); background_chain = NULL; glview = NULL; } @@ -67,16 +74,81 @@ AbstractNode *find_root_tag(AbstractNode *n) return NULL; } +string info_dump(OffscreenView *glview) +{ + assert(glview); + +#ifdef __GNUG__ +#define compiler_info "GCC " << __VERSION__ +#elif defined(_MSC_VER) +#define compiler_info "MSVC " << _MSC_FULL_VER +#else +#define compiler_info "unknown compiler" +#endif + + std::stringstream out; +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + out << "\nOpenSCAD Version: " << TOSTRING(OPENSCAD_VERSION) + << "\nCompiled by: " << compiler_info + << "\nCompile date: " << __DATE__ + << "\nBoost version: " << BOOST_LIB_VERSION + << "\nEigen version: " << EIGEN_WORLD_VERSION << "." + << EIGEN_MAJOR_VERSION << "." << EIGEN_MINOR_VERSION + // << "\nCGAL version: " << CGAL_VERSION ??? + // << "\nOpenCSG" << ??? + << "\n" << glview->getInfo() + << "\n"; + + return out.str(); +} + +po::variables_map parse_options(int argc, char *argv[]) +{ + po::options_description desc("Allowed options"); + desc.add_options() + ("help,h", "help message")//; + ("info,i", "information on GLEW, OpenGL, OpenSCAD, and OS")//; + +// po::options_description hidden("Hidden options"); +// hidden.add_options() + ("input-file", po::value< vector<string> >(), "input file") + ("output-file", po::value< vector<string> >(), "ouput file"); + + po::positional_options_description p; + p.add("input-file", 1).add("output-file", 1); + + po::options_description all_options; + all_options.add(desc); // .add(hidden); + + po::variables_map vm; + po::store(po::command_line_parser(argc, argv).options(all_options).positional(p).run(), vm); + po::notify(vm); + + return vm; +} + int csgtestcore(int argc, char *argv[], test_type_e test_type) { - if (argc != 3) { - fprintf(stderr, "Usage: %s <file.scad> <output.png>\n", argv[0]); + bool sysinfo_dump = false; + const char *filename, *outfilename = NULL; + po::variables_map vm; + try { + vm = parse_options(argc, argv); + } catch ( po::error e ) { + cerr << "error parsing options\n"; + } + if (vm.count("info")) sysinfo_dump = true; + if (vm.count("input-file")) + filename = vm["input-file"].as< vector<string> >().begin()->c_str(); + if (vm.count("output-file")) + outfilename = vm["output-file"].as< vector<string> >().begin()->c_str(); + + if ((!filename || !outfilename) && !sysinfo_dump) { + cerr << "Usage: " << argv[0] << " <file.scad> <output.png>\n"; exit(1); } - const char *filename = argv[1]; - const char *outfilename = argv[2]; - Builtins::instance()->initialize(); QApplication app(argc, argv, false); @@ -110,7 +182,11 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type) AbstractModule *root_module; ModuleInstantiation root_inst; - root_module = parsefile(filename); + if (sysinfo_dump) + root_module = parse("sphere();","",false); + else + root_module = parsefile(filename); + if (!root_module) { exit(1); } @@ -194,6 +270,7 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type) fprintf(stderr,"Can't create OpenGL OffscreenView. Code: %i. Exiting.\n", error); exit(1); } + if (sysinfo_dump) cout << info_dump(csgInfo.glview); BoundingBox bbox = csgInfo.root_chain->getBoundingBox(); Vector3d center = (bbox.min() + bbox.max()) / 2; diff --git a/tests/fbo.cc b/tests/fbo.cc index 2a3342d..a6677c1 100644 --- a/tests/fbo.cc +++ b/tests/fbo.cc @@ -93,6 +93,7 @@ bool fbo_ext_init(fbo_t *fbo, size_t width, size_t height) glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthbuf_id); if (report_glerror("specifying depth render buffer EXT")) return false; + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthbuf_id); if (report_glerror("specifying stencil render buffer EXT")) return false; @@ -142,7 +143,12 @@ bool fbo_arb_init(fbo_t *fbo, size_t width, size_t height) return false; } - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + //glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + // to prevent Mesa's software renderer from crashing, do this in two stages. + // ie. instead of using GL_DEPTH_STENCIL_ATTACHMENT, do DEPTH then STENCIL. + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, fbo->depthbuf_id); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->depthbuf_id); if (report_glerror("specifying depth stencil render buffer")) return false; @@ -183,24 +189,25 @@ bool fbo_resize(fbo_t *fbo, size_t width, size_t height) glBindRenderbufferEXT(GL_RENDERBUFFER, fbo->depthbuf_id); if (glewIsSupported("GL_EXT_packed_depth_stencil")) { glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); - if (report_glerror("creating depth stencil render buffer")) return false; + if (report_glerror("creating EXT depth stencil render buffer")) return false; } else { glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); - if (report_glerror("creating depth render buffer")) return false; + if (report_glerror("creating EXT depth render buffer")) return false; } glBindRenderbufferEXT(GL_RENDERBUFFER, fbo->renderbuf_id); glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_RGBA8, width, height); - if (report_glerror("creating color render buffer")) return false; + if (report_glerror("creating EXT color render buffer")) return false; } else { + glBindRenderbuffer(GL_RENDERBUFFER, fbo->renderbuf_id); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); + if (report_glerror("creating color render buffer")) return false; + glBindRenderbuffer(GL_RENDERBUFFER, fbo->depthbuf_id); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); if (report_glerror("creating depth stencil render buffer")) return false; - glBindRenderbuffer(GL_RENDERBUFFER, fbo->renderbuf_id); - glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); - if (report_glerror("creating color render buffer")) return false; } return true; diff --git a/tests/system-gl.cc b/tests/system-gl.cc index f95a5ca..2e3f3bc 100644 --- a/tests/system-gl.cc +++ b/tests/system-gl.cc @@ -2,34 +2,40 @@ /* OpenGL helper functions */ #include <iostream> +#include <sstream> +#include <string> #include "system-gl.h" #include <boost/algorithm/string.hpp> using namespace std; using namespace boost; -void glew_dump() { - cerr << "GLEW version: " << glewGetString(GLEW_VERSION) << endl - << "Renderer: " << (const char *)glGetString(GL_RENDERER) << endl - << "Vendor: " << (const char *)glGetString(GL_VENDOR) << endl - << "OpenGL version: " << (const char *)glGetString(GL_VERSION) << endl; +string glew_dump(bool dumpall) +{ + stringstream out; + out << "GLEW version: " << glewGetString(GLEW_VERSION) << endl + << "GL Renderer: " << (const char *)glGetString(GL_RENDERER) << endl + << "GL Vendor: " << (const char *)glGetString(GL_VENDOR) << endl + << "OpenGL Version: " << (const char *)glGetString(GL_VERSION) << endl; - bool dumpall = false; + out << "GL Extensions: " << endl; if (dumpall) { string extensions((const char *)glGetString(GL_EXTENSIONS)); replace_all( extensions, " ", "\n " ); - cerr << "Extensions: " << endl << " " << extensions << endl; + out << " " << extensions << endl; } - cerr << " GL_ARB_framebuffer_object: " - << (glewIsSupported("GL_ARB_framebuffer_object") ? "yes" : "no") - << endl - << " GL_EXT_framebuffer_object: " - << (glewIsSupported("GL_EXT_framebuffer_object") ? "yes" : "no") - << endl - << " GL_EXT_packed_depth_stencil: " - << (glewIsSupported("GL_EXT_packed_depth_stencil") ? "yes" : "no") - << endl; + out << "GL_ARB_framebuffer_object: " + << (glewIsSupported("GL_ARB_framebuffer_object") ? "yes" : "no") + << endl + << "GL_EXT_framebuffer_object: " + << (glewIsSupported("GL_EXT_framebuffer_object") ? "yes" : "no") + << endl + << "GL_EXT_packed_depth_stencil: " + << (glewIsSupported("GL_EXT_packed_depth_stencil") ? "yes" : "no") + << endl; + + return out.str(); }; bool report_glerror(const char * function) diff --git a/tests/system-gl.h b/tests/system-gl.h index bb41be5..45d5130 100644 --- a/tests/system-gl.h +++ b/tests/system-gl.h @@ -2,8 +2,9 @@ #define SYSTEMGL_H_ #include <GL/glew.h> +#include <string> -void glew_dump(); +std::string glew_dump(bool dumpall); bool report_glerror(const char *task); #endif diff --git a/tests/test_cmdline_tool.py b/tests/test_cmdline_tool.py index 688026e..3e9f45a 100755 --- a/tests/test_cmdline_tool.py +++ b/tests/test_cmdline_tool.py @@ -64,16 +64,21 @@ def compare_text(expected, actual): return get_normalized_text(expected) == get_normalized_text(actual) def compare_default(resultfilename): + print >> sys.stderr, 'diff text compare: ' + print >> sys.stderr, ' expected textfile: ', expectedfilename + print >> sys.stderr, ' actual textfile: ', resultfilename if not compare_text(expectedfilename, resultfilename): execute_and_redirect("diff", [expectedfilename, resultfilename], sys.stderr) return False return True def compare_png(resultfilename): + print >> sys.stderr, 'Yee image compare:' + print >> sys.stderr, ' expected image: ', expectedfilename if not resultfilename: - print >> sys.stderr, "Error: OpenSCAD did not generate an image" + print >> sys.stderr, "Error: OpenSCAD did not generate an image to test" return False - print >> sys.stderr, 'Yee image compare: ', expectedfilename, ' ', resultfilename + print >> sys.stderr, ' actual image: ', resultfilename if execute_and_redirect("./yee_compare", [expectedfilename, resultfilename, "-downsample", "2", "-threshold", "300"], sys.stderr) != 0: return False return True diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py new file mode 100755 index 0000000..897f7b8 --- /dev/null +++ b/tests/test_pretty_print.py @@ -0,0 +1,321 @@ +#!/usr/bin/python +# +# This program 'pretty prints' the ctest output, namely +# files from builddir/Testing/Temporary. +# html & wiki output are produced +# wiki uploading is available by running +# +# python test_pretty_print.py --upload + +# todo +# ban opencsg<2.0 from opencsgtest +# copy all images, sysinfo.txt to bundle for html/upload (images +# can be altered by subsequent runs) +# figure out hwo to make the thing run after the test +# figure out how CTEST treats the logfiles. +# why is hash differing +# instead of having special '-info' prerun, put it as yet-another-test +# and parse the log +# provide option to replace 'expected' images on wiki +# (yes sometimes you do need to change/update them) + +import string,sys,re,os,hashlib,subprocess + +def tryread(filename): + data = None + try: + print 'reading', filename + f = open(filename) + data = f.read() + f.close() + except: + print 'couldn\'t open ',filename + return data + +def trysave(data,filename): + try: + f=open(filename,'w') + print 'writing',len(data),'bytes to',filename + f.write(data) + f.close() + except: + print 'problem writing to',filename + return None + return True + +def ezsearch(pattern,str): + x = re.search(pattern,str,re.DOTALL|re.MULTILINE) + if x and len(x.groups())>0: return x.group(1).strip() + return '' + +def read_gitinfo(): + # won't work if run from outside of branch. + data = subprocess.Popen(['git','remote','-v'],stdout=subprocess.PIPE).stdout.read() + origin = ezsearch('^origin *?(.*?)\(fetch.*?$',data) + upstream = ezsearch('^upstream *?(.*?)\(fetch.*?$',data) + data = subprocess.Popen(['git','branch'],stdout=subprocess.PIPE).stdout.read() + branch = ezsearch('^\*(.*?)$',data) + out = 'Git branch: ' + branch + ' from origin ' + origin + '\n' + out += 'Git upstream: ' + upstream + '\n' + return out + +def read_sysinfo(filename): + data = tryread(filename) + if not data: return 'sysinfo: unknown' + + machine = ezsearch('Machine:(.*?)\n',data) + machine = machine.replace(' ','-').replace('/','-') + + osinfo = ezsearch('OS info:(.*?)\n',data) + osplain = osinfo.split(' ')[0].strip().replace('/','-') + if 'windows' in osinfo.lower(): osplain = 'win' + + renderer = ezsearch('GL Renderer:(.*?)\n',data) + tmp = renderer.split(' ') + tmp = string.join(tmp[0:3],'-') + tmp = tmp.split('/')[0] + renderer = tmp + + hexhash = hashlib.md5() + hexhash.update(data) + hexhash = hexhash.hexdigest()[-4:].upper() + hash = '' + for c in hexhash: hash += chr(ord(c)+97-48) + + sysid = osplain + '_' + machine + '_' + renderer + '_' + hash + sysid = sysid.lower() + + data += read_gitinfo() + + data += 'Image comparison: PerceptualDiff by H. Yee' + return data, sysid + +class Test: + def __init__(self,fullname,time,passed,output,type,actualfile,expectedfile,scadfile,log): + self.fullname,self.time,self.passed,self.output = \ + fullname, time, passed, output + self.type, self.actualfile, self.expectedfile, self.scadfile = \ + type, actualfile, expectedfile, scadfile + self.fulltestlog = log + + def __str__(self): + x = 'fullname: ' + self.fullname + x+= '\nactualfile: ' + self.actualfile + x+= '\nexpectedfile: ' + self.expectedfile + x+= '\ntesttime: ' + self.time + x+= '\ntesttype: ' + self.type + x+= '\npassed: ' + str(self.passed) + x+= '\nscadfile: ' + self.scadfile + x+= '\noutput bytes: ' + str(len(self.output)) + x+= '\ntestlog bytes: ' + str(len(self.fulltestlog)) + x+= '\n' + return x + +def parsetest(teststring): + patterns = ["Test:(.*?)\n", # fullname + "Test time =(.*?) sec\n", + "Test time.*?Test (Passed)", + "Output:(.*?)<end of output>", + 'Command:.*?-s" "(.*?)"', # type + "actual .*?:(.*?)\n", + "expected .*?:(.*?)\n", + 'Command:.*?(testdata.*?)"' # scadfile + ] + hits = map( lambda pattern: ezsearch(pattern,teststring), patterns ) + test = Test(hits[0],hits[1],hits[2]=='Passed',hits[3],hits[4],hits[5],hits[6],hits[7],teststring) + return test + +def parselog(data): + startdate = ezsearch('Start testing: (.*?)\n',data) + enddate = ezsearch('End testing: (.*?)\n',data) + pattern = '([0-9]*/[0-9]* Testing:.*?time elapsed.*?\n)' + test_chunks = re.findall(pattern,data,re.S) + tests = map( parsetest, test_chunks ) + print 'found', len(tests),'test results' + return startdate, tests, enddate + +def wikify_filename(testname,filename,sysid): + # translate from local system to wiki style filename. + result = wiki_rootpath+'_'+testname+'_' + expected = ezsearch('(expected....$)',filename) + if expected!='': result += expected + actual = ezsearch(os.sep+'.*?-output.*?(actual.*)',filename) + if actual!='': + result += sysid+'_'+actual + return result.replace('/','_') + + +def towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, testlog): + wiki_template = """ +<h3>[[WIKI_ROOTPATH]] test run report</h3> + +'''Sysid''': SYSID + +'''Result summary''': NUMPASSED / NUMTESTS tests passed ( PERCENTPASSED % ) <br> + +'''System info''': +<pre> +SYSINFO +</pre> + +start time: STARTDATE <br> +end time : ENDDATE <br> + +'''Failed image tests''' + +{| border=1 cellspacing=0 cellpadding=1 +! Testname !! expected output !! actual output +<REPEAT1> +|- +| FTESTNAME || [[File:EXPECTEDFILE|thumb|250px]] || ACTUALFILE_WIKI +</REPEAT1> +|} + +'''Failed text tests''' + +{|border=1 cellspacing=0 cellpadding=1 +! Testname +<REPEAT2> +|- +| FTESTNAME +</REPEAT2> +|} + +'''Test logs''' + +(excerpted from Testing/Temporary/LastTest.Log) + +<pre> +FAILED_TESTLOGS +</pre> + +""" + numpassed = len(filter(lambda x: x.passed, tests)) + percent = str(int(100.0*numpassed / len(tests))) + manifest = {} + s = wiki_template + repeat1 = ezsearch('(<REPEAT1>.*?</REPEAT1>)',s) + repeat2 = ezsearch('(<REPEAT2>.*?</REPEAT2>)',s) + dic = { 'STARTDATE': startdate, 'ENDDATE': enddate, 'WIKI_ROOTPATH': wiki_rootpath, + 'SYSINFO': sysinfo, 'SYSID':sysid, 'LASTTESTLOG':testlog, + 'NUMTESTS':len(tests), 'NUMPASSED':numpassed, 'PERCENTPASSED':percent } + for key in dic.keys(): + s = re.sub(key,str(dic[key]),s) + testlogs = '' + for t in tests: + # if t.passed: noop + if not t.passed: + testlogs += '\n\n'+t.fulltestlog + if t.type=='txt': + newchunk = re.sub('FTEST_OUTPUTFILE',t.fullname,repeat2) + newchunk = re.sub('FTESTNAME',t.fullname,repeat2) + s = s.replace(repeat2, newchunk+repeat2) + elif t.type=='png': + manifest[t.actualfile] = wikify_filename(t.fullname,t.actualfile,sysid) + manifest[t.expectedfile] = wikify_filename(t.fullname,t.expectedfile,sysid) + if t.actualfile: + actualfile_wiki = '[[File:'+manifest[t.actualfile]+'|thumb|250px]]' + else: + actualfile_wiki = 'No file generated.<br/>See log for details' + newchunk = re.sub('FTESTNAME',t.fullname,repeat1) + newchunk = newchunk.replace('ACTUALFILE_WIKI',actualfile_wiki) + newchunk = newchunk.replace('EXPECTEDFILE',manifest[t.expectedfile]) + s = s.replace(repeat1, newchunk+repeat1) + s = s.replace('FAILED_TESTLOGS',testlogs) + s = s.replace(repeat1,'') + s = s.replace(repeat2,'') + s = re.sub('<REPEAT.*?>\n','',s) + s = re.sub('</REPEAT.*?>','',s) + return manifest, s + + +def wikitohtml(wiki_rootpath, sysid, wikidata, manifest): + head = '<html><head><title>'+wiki_rootpath+' test run for '+sysid +'</title></head><body>' + revmanifest = dict((val,key) for key, val in manifest.iteritems()) + x=re.sub('\{\|(.*?)\n','<table \\1>\n',wikidata) + x=re.sub("'''(.*?)'''","<b>\\1</b>",x) + filestrs=re.findall('\[\[File\:(.*?)\|.*?\]\]',x) + for f in filestrs: + newfile_html='<img src="'+revmanifest[f]+'" width=250/>' + x=re.sub('\[\[File\:'+f+'\|.*?\]\]',newfile_html,x) + dic = { '|}':'</table>', '|-':'<tr>', '||':'<td>', '|':'<td>', + '!!':'<th>', '!':'<tr><th>', '\n\n':'\n<p>\n'} #order matters + for key in dic: x=x.replace(key,dic[key]) + x=re.sub("\[\[(.*?)\]\]","\\1",x) + return head + x + '</body></html>' + +def upload_dryrun(wikiurl,api_php_path,wikidata,manifest,wiki_rootpath,sysid,botname,botpass): + print 'dry run. no files to be uploaded' + print 'log in', wikiurl, api_php_path, botname, botpass + print 'save ' + '*[['+wiki_rootpath+sysid+']]' + ' to page ' + wiki_rootpath + print 'save ', len(wikidata), ' bytes to page ',wiki_rootpath+sysid + for localfile in manifest.keys(): + if localfile: + localf=open(localfile) + wikifile = manifest[localfile] + print 'upload',localfile,wikifile + +def upload(wikiurl,api_php_path,wikidata,manifest,wiki_rootpath,sysid,botname,botpass,dryrun=True): + if dryrun: + upload_dryrun(wikiurl,api_php_path,wikidata,manifest,wiki_rootpath,sysid,botname,botpass) + return None + try: + import mwclient + except: + print 'please download mwclient and unpack here:', os.cwd() + print 'open site',wikiurl + if not api_php_path == '': + site = mwclient.Site(wikiurl,api_php_path) + else: + site = mwclient.Site(wikiurl) + + print 'bot login' + site.login(botname,botpass) + + print 'edit ',wiki_rootpath + page = site.Pages[wiki_rootpath] + text = page.edit() + rootpage = wiki_rootpath + sysid + if not '[['+rootpage+']]' in text: + page.save(text +'\n*[['+rootpage+']]\n') + + print 'upload wiki data to',rootpage + page = site.Pages[rootpage] + text = page.edit() + page.save(wikidata) + + print 'upload images' + for localfile in sorted(manifest.keys()): + if localfile: + localf=open(localfile) + wikifile = manifest[localfile] + skip=False + if 'expected.png' in wikifile.lower(): + image = site.Images[wikifile] + if image.exists: + print 'skipping ',wikifile, '(expected image, already on wiki)' + skip=True + if not skip: + print wikifile,'...' + site.upload(localf,wikifile,wiki_rootpath + ' test', ignore=True) + +wikisite = 'cakebaby.referata.com' +wiki_rootpath = 'OpenSCAD' +builddir = os.getcwd() +logpath = os.path.join(builddir,'Testing','Temporary') +logfilename = os.path.join(logpath,'LastTest.log') + +def main(): + testlog = tryread(logfilename) + startdate, tests, enddate = parselog(testlog) + tests = sorted(tests, key = lambda t:t.passed) + sysinfo, sysid = read_sysinfo('sysinfo.txt') + if '--hack' in sys.argv: sysid+='_hack' + manifest, wikidata = towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, testlog) + trysave(wikidata, os.path.join(logpath,sysid+'.wiki')) + htmldata = wikitohtml(wiki_rootpath, sysid, wikidata, manifest) + trysave(htmldata, os.path.join(logpath,sysid+'.html')) + if '--upload' in sys.argv: + upload(wikisite,'',wikidata,manifest,wiki_rootpath,sysid,'openscadbot','tobdacsnepo',dryrun=False) +main() + |