Implement a command-line interface.

This commit adds a basic command-line interface. This interface
allows rendering thumbnails and exporting data in batch mode.
pull/36/merge
whitequark 2016-11-29 02:57:41 +00:00
parent dbc567ed89
commit 47244c5e89
11 changed files with 422 additions and 87 deletions

View File

@ -29,6 +29,7 @@ New rendering features:
* The "Show/hide outlines" button is now independent from "Show/hide edges". * The "Show/hide outlines" button is now independent from "Show/hide edges".
Other new features: Other new features:
* New command-line interface, for batch exporting and more.
* New command for measuring total length of selected entities, * New command for measuring total length of selected entities,
"Analyze → Measure Perimeter". "Analyze → Measure Perimeter".
* New link to match the on-screen size of the sketch with its actual size, * New link to match the on-screen size of the sketch with its actual size,

View File

@ -9,28 +9,22 @@ before_build:
- cmake -G"Visual Studio 12" -T v120 .. - cmake -G"Visual Studio 12" -T v120 ..
build_script: build_script:
- msbuild "src\solvespace.vcxproj" /verbosity:minimal /property:Configuration=%BUILD_TYPE% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" - msbuild "src\solvespace.vcxproj" /verbosity:minimal /property:Configuration=%BUILD_TYPE% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
- msbuild "test\solvespace_testsuite.vcxproj" /verbosity:minimal /property:Configuration=%BUILD_TYPE% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" - msbuild "src\solvespace-cli.vcxproj" /verbosity:minimal /property:Configuration=%BUILD_TYPE% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
- msbuild "test\solvespace-testsuite.vcxproj" /verbosity:minimal /property:Configuration=%BUILD_TYPE% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
test_script: test_script:
- bin\%BUILD_TYPE%\solvespace_testsuite.exe - bin\%BUILD_TYPE%\solvespace-testsuite.exe
artifacts: artifacts:
- path: build\bin\%BUILD_TYPE%\solvespace.exe - path: build\bin\%BUILD_TYPE%\solvespace.exe
name: solvespace.exe name: solvespace.exe
- path: build\bin\%BUILD_TYPE%\solvespace-cli.exe
name: solvespace-cli.exe
- path: build\bin\%BUILD_TYPE%\solvespace.pdb - path: build\bin\%BUILD_TYPE%\solvespace.pdb
name: solvespace.pdb name: solvespace.pdb
deploy: deploy:
# Releases to solvespace/solvespace
- provider: GitHub - provider: GitHub
auth_token: auth_token:
secure: P9/pf2nM+jlWKe7pCjMp41HycBNP/+5AsmE/TETrDUoBOa/9WFHelqdVFrbRn9IC secure: P9/pf2nM+jlWKe7pCjMp41HycBNP/+5AsmE/TETrDUoBOa/9WFHelqdVFrbRn9IC
description: "" description: ""
artifact: solvespace.exe artifact: solvespace.exe,solvespace-cli.exe,solvespace.pdb
on:
appveyor_repo_tag: true
# Releases to whitequark/solvespace (to be removed)
- provider: GitHub
auth_token:
secure: Flqxu1cz6PyxVT1wzTP4bSrQOY8wFrO7pJxYxvjEkLqIUU4dsDQrs2rac/A9deet
description: ""
artifact: solvespace.exe
on: on:
appveyor_repo_tag: true appveyor_repo_tag: true

View File

@ -5,12 +5,13 @@ foreach(pkg_config_lib CAIRO)
link_directories(${${pkg_config_lib}_LIBRARY_DIRS}) link_directories(${${pkg_config_lib}_LIBRARY_DIRS})
endforeach() endforeach()
add_executable(solvespace_benchmark add_executable(solvespace-benchmark
harness.cpp harness.cpp
$<TARGET_PROPERTY:resources,EXTRA_SOURCES>) $<TARGET_PROPERTY:resources,EXTRA_SOURCES>)
target_link_libraries(solvespace_benchmark target_link_libraries(solvespace-benchmark
solvespace_headless) solvespace-core
solvespace-headless)
add_dependencies(solvespace_benchmark add_dependencies(solvespace-benchmark
resources) resources)

View File

@ -127,7 +127,7 @@ endif()
# solvespace library # solvespace library
set(solvespace_cad_HEADERS set(solvespace_core_HEADERS
config.h config.h
dsc.h dsc.h
expr.h expr.h
@ -139,7 +139,7 @@ set(solvespace_cad_HEADERS
render/gl2shader.h render/gl2shader.h
srf/surface.h) srf/surface.h)
set(solvespace_cad_SOURCES set(solvespace_core_SOURCES
bsp.cpp bsp.cpp
clipboard.cpp clipboard.cpp
confscreen.cpp confscreen.cpp
@ -186,16 +186,16 @@ set(solvespace_cad_SOURCES
srf/surfinter.cpp srf/surfinter.cpp
srf/triangulate.cpp) srf/triangulate.cpp)
set(solvespace_cad_gl_SOURCES set(solvespace_core_gl_SOURCES
export.cpp export.cpp
solvespace.cpp) solvespace.cpp)
add_library(solvespace_cad STATIC add_library(solvespace-core STATIC
${util_SOURCES} ${util_SOURCES}
${solvespace_cad_HEADERS} ${solvespace_core_HEADERS}
${solvespace_cad_SOURCES}) ${solvespace_core_SOURCES})
target_link_libraries(solvespace_cad target_link_libraries(solvespace-core
dxfrw dxfrw
${util_LIBRARIES} ${util_LIBRARIES}
${ZLIB_LIBRARY} ${ZLIB_LIBRARY}
@ -203,13 +203,13 @@ target_link_libraries(solvespace_cad
${FREETYPE_LIBRARY} ${FREETYPE_LIBRARY}
${Backtrace_LIBRARIES}) ${Backtrace_LIBRARIES})
target_compile_options(solvespace_cad target_compile_options(solvespace-core
PRIVATE ${COVERAGE_FLAGS}) PRIVATE ${COVERAGE_FLAGS})
# solvespace gui executable # solvespace graphical executable
add_executable(solvespace WIN32 MACOSX_BUNDLE add_executable(solvespace WIN32 MACOSX_BUNDLE
${solvespace_cad_gl_SOURCES} ${solvespace_core_gl_SOURCES}
${platform_SOURCES} ${platform_SOURCES}
$<TARGET_PROPERTY:resources,EXTRA_SOURCES>) $<TARGET_PROPERTY:resources,EXTRA_SOURCES>)
@ -217,69 +217,93 @@ add_dependencies(solvespace
resources) resources)
target_link_libraries(solvespace target_link_libraries(solvespace
solvespace_cad solvespace-core
${OPENGL_LIBRARIES} ${OPENGL_LIBRARIES}
${platform_LIBRARIES} ${platform_LIBRARIES}
${COVERAGE_LIBRARY}) ${COVERAGE_LIBRARY})
if(WIN32 AND NOT MINGW) if(MSVC)
set_target_properties(solvespace PROPERTIES set_target_properties(solvespace PROPERTIES
LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO") LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO")
endif() endif()
if(APPLE)
foreach(lib ${platform_BUNDLED_LIBS})
get_filename_component(name ${lib} NAME)
set(target ${CMAKE_CURRENT_BINARY_DIR}/solvespace.app/Contents/MacOS/${name})
execute_process(COMMAND otool -D ${lib}
OUTPUT_VARIABLE canonical_lib OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REGEX REPLACE "^.+:\n" "" canonical_lib ${canonical_lib})
add_custom_command(TARGET solvespace POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${lib} ${target}
COMMAND install_name_tool -change ${canonical_lib} @executable_path/${name}
$<TARGET_FILE:solvespace>
COMMENT "Bundling shared library ${lib}"
VERBATIM)
endforeach()
set(bundle solvespace)
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${bundle}.dmg
COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/${bundle}.dmg
COMMAND hdiutil create -srcfolder ${CMAKE_CURRENT_BINARY_DIR}/${bundle}.app
${CMAKE_BINARY_DIR}/${bundle}.dmg
DEPENDS $<TARGET_FILE:${bundle}>
COMMENT "Building ${bundle}.dmg"
VERBATIM)
add_custom_target(${bundle}-dmg ALL
DEPENDS ${CMAKE_BINARY_DIR}/${bundle}.dmg)
endif()
if(NOT WIN32)
install(TARGETS solvespace
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
BUNDLE DESTINATION .)
endif()
# solvespace headless library # solvespace headless library
set(headless_SOURCES set(headless_SOURCES
platform/headless.cpp platform/headless.cpp
render/rendercairo.cpp) render/rendercairo.cpp)
add_library(solvespace_headless STATIC EXCLUDE_FROM_ALL add_library(solvespace-headless STATIC EXCLUDE_FROM_ALL
${solvespace_cad_gl_SOURCES} ${solvespace_core_gl_SOURCES}
${headless_SOURCES}) ${headless_SOURCES})
target_compile_definitions(solvespace_headless target_compile_definitions(solvespace-headless
PRIVATE -DHEADLESS) PRIVATE -DHEADLESS)
target_include_directories(solvespace_headless target_include_directories(solvespace-headless
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(solvespace_headless target_link_libraries(solvespace-headless
solvespace_cad solvespace-core
${CAIRO_LIBRARIES}) ${CAIRO_LIBRARIES})
target_compile_options(solvespace_headless target_compile_options(solvespace-headless
PRIVATE ${COVERAGE_FLAGS}) PRIVATE ${COVERAGE_FLAGS})
# solvespace command-line executable
add_executable(solvespace-cli
platform/climain.cpp
$<TARGET_PROPERTY:resources,EXTRA_SOURCES>)
target_link_libraries(solvespace-cli
solvespace-core
solvespace-headless)
add_dependencies(solvespace-cli
resources)
# solvespace unix package
if(NOT (WIN32 OR APPLE))
install(TARGETS solvespace solvespace-cli
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
# solvespace macOS package
if(APPLE)
set(bundle solvespace)
set(bundle_bin ${EXECUTABLE_OUTPUT_PATH}/${bundle}.app/Contents/MacOS)
add_custom_command(TARGET solvespace POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:solvespace-cli> ${bundle_bin}
COMMENT "Bundling executable solvespace-cli"
VERBATIM)
foreach(lib ${platform_BUNDLED_LIBS})
get_filename_component(name ${lib} NAME)
execute_process(COMMAND otool -D ${lib}
OUTPUT_VARIABLE canonical_lib OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REGEX REPLACE "^.+:\n" "" canonical_lib ${canonical_lib})
add_custom_command(TARGET ${bundle} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${lib} ${bundle_bin}/${name}
COMMAND install_name_tool -change ${canonical_lib} @executable_path/${name}
$<TARGET_FILE:${bundle}>
COMMAND install_name_tool -change ${canonical_lib} @executable_path/${name}
$<TARGET_FILE:solvespace-cli>
COMMENT "Bundling shared library ${lib}"
VERBATIM)
endforeach()
add_custom_command(OUTPUT ${EXECUTABLE_OUTPUT_PATH}/${bundle}.dmg
COMMAND ${CMAKE_COMMAND} -E remove ${EXECUTABLE_OUTPUT_PATH}/${bundle}.dmg
COMMAND hdiutil create -srcfolder ${EXECUTABLE_OUTPUT_PATH}/${bundle}.app
${EXECUTABLE_OUTPUT_PATH}/${bundle}.dmg
DEPENDS $<TARGET_FILE:${bundle}>
COMMENT "Building ${bundle}.dmg"
VERBATIM)
add_custom_target(${bundle}-dmg ALL
DEPENDS ${EXECUTABLE_OUTPUT_PATH}/${bundle}.dmg)
endif()

317
src/platform/climain.cpp Normal file
View File

@ -0,0 +1,317 @@
//-----------------------------------------------------------------------------
// Our main() function for the command-line interface.
//
// Copyright 2016 whitequark
//-----------------------------------------------------------------------------
#include "solvespace.h"
namespace SolveSpace {
// These are defined in headless.cpp, and aren't exposed in solvespace.h.
extern std::shared_ptr<Pixmap> framebuffer;
}
static void ShowUsage(const char *argv0) {
fprintf(stderr, "Usage: %s <command> <options> <filename> [filename...]", argv0);
//-----------------------------------------------------------------------------> 80 col */
fprintf(stderr, R"(
When run, performs an action specified by <command> on every <filename>.
Common options:
-o, --output <pattern>
For an input file <basename>.slvs, replaces the '%%' symbol in <pattern>
with <basename> and uses it as output file. For example, when using
--output %%-2d.png for input files a.slvs and b.slvs, output files
a-2d.png and b-2d.png will be written.
-v, --view <direction>
Selects the camera direction. <direction> can be one of "top", "bottom",
"left", "right", "front", "back", or "isometric".
-t, --chord-tol <tolerance>
Selects the chord tolerance, used for converting exact curves to
piecewise linear, and exact surfaces into triangle meshes.
For export commands, the unit is mm, and the default is 1.0 mm.
For non-export commands, the unit is %%, and the default is 1.0 %%.
Commands:
thumbnail --output <pattern> --size <size> --view <direction>
[--chord-tol <tolerance>]
Outputs a rendered view of the sketch, like the SolveSpace GUI would.
<size> is <width>x<height>, in pixels. Graphics acceleration is
not used, and the output may look slightly different from the GUI.
export-view --output <pattern> --view <direction> [--chord-tol <tolerance>]
Exports a view of the sketch, in a 2d vector format.
export-wireframe --output <pattern> [--chord-tol <tolerance>]
Exports a wireframe of the sketch, in a 3d vector format.
export-mesh --output <pattern> [--chord-tol <tolerance>]
Exports a triangle mesh of solids in the sketch, with exact surfaces
being triangulated first.
export-surfaces --output <pattern>
Exports exact surfaces of solids in the sketch, if any.
)");
auto FormatListFromFileFilter = [](const FileFilter *filter) {
std::string descr;
while(filter->name) {
descr += "\n ";
descr += filter->name;
descr += " (";
const char *const *patterns = filter->patterns;
while(*patterns) {
descr += *patterns;
if(*++patterns) {
descr += ", ";
}
}
descr += ")";
filter++;
}
return descr;
};
fprintf(stderr, R"(
File formats:
thumbnail:%s
export-view:%s
export-wireframe:%s
export-mesh:%s
export-surfaces:%s
)", FormatListFromFileFilter(PngFileFilter).c_str(),
FormatListFromFileFilter(VectorFileFilter).c_str(),
FormatListFromFileFilter(Vector3dFileFilter).c_str(),
FormatListFromFileFilter(MeshFileFilter).c_str(),
FormatListFromFileFilter(SurfaceFileFilter).c_str());
}
static bool RunCommand(size_t argc, char **argv) {
if(argc < 2) return false;
std::function<void(const std::string &)> runner;
std::vector<std::string> inputFiles;
auto ParseInputFile = [&](size_t &argn) {
std::string arg = argv[argn];
if(arg[0] != '-') {
inputFiles.push_back(arg);
return true;
} else return false;
};
std::string outputPattern;
auto ParseOutputPattern = [&](size_t &argn) {
if(argn + 1 < argc && (!strcmp(argv[argn], "--output") ||
!strcmp(argv[argn], "-o"))) {
argn++;
outputPattern = argv[argn];
return true;
} else return false;
};
Vector projUp, projRight;
auto ParseViewDirection = [&](size_t &argn) {
if(argn + 1 < argc && (!strcmp(argv[argn], "--view") ||
!strcmp(argv[argn], "-v"))) {
argn++;
if(!strcmp(argv[argn], "top")) {
projRight = Vector::From(1, 0, 0);
projUp = Vector::From(0, 1, 0);
} else if(!strcmp(argv[argn], "bottom")) {
projRight = Vector::From(-1, 0, 0);
projUp = Vector::From(0, 1, 0);
} else if(!strcmp(argv[argn], "left")) {
projRight = Vector::From(0, 1, 0);
projUp = Vector::From(0, 0, 1);
} else if(!strcmp(argv[argn], "right")) {
projRight = Vector::From(0, -1, 0);
projUp = Vector::From(0, 0, 1);
} else if(!strcmp(argv[argn], "front")) {
projRight = Vector::From(-1, 0, 0);
projUp = Vector::From(0, 0, 1);
} else if(!strcmp(argv[argn], "back")) {
projRight = Vector::From(1, 0, 0);
projUp = Vector::From(0, 0, 1);
} else if(!strcmp(argv[argn], "isometric")) {
projRight = Vector::From(0.707, 0.000, -0.707);
projUp = Vector::From(-0.408, 0.816, -0.408);
} else {
fprintf(stderr, "Unrecognized view direction '%s'\n", argv[argn]);
}
return true;
} else return false;
};
double chordTol = 1.0;
auto ParseChordTolerance = [&](size_t &argn) {
if(argn + 1 < argc && (!strcmp(argv[argn], "--chord-tol") ||
!strcmp(argv[argn], "-t"))) {
argn++;
if(sscanf(argv[argn], "%lf", &chordTol) == 1) {
return true;
} else return false;
} else return false;
};
if(!strcmp(argv[1], "thumbnail")) {
unsigned width, height;
auto ParseSize = [&](size_t &argn) {
if(argn + 1 < argc && !strcmp(argv[argn], "--size")) {
argn++;
if(sscanf(argv[argn], "%ux%u", &width, &height) == 2) {
return true;
} else return false;
} else return false;
};
for(size_t argn = 2; argn < argc; argn++) {
if(!(ParseInputFile(argn) ||
ParseOutputPattern(argn) ||
ParseViewDirection(argn) ||
ParseChordTolerance(argn) ||
ParseSize(argn))) {
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
return false;
}
}
if(width == 0 || height == 0) {
fprintf(stderr, "Non-zero viewport size must be specified.\n");
return false;
}
if(EXACT(projUp.Magnitude() == 0 || projRight.Magnitude() == 0)) {
fprintf(stderr, "View direction must be specified.\n");
return false;
}
runner = [&](const std::string &output) {
SS.GW.width = width;
SS.GW.height = height;
SS.GW.projRight = projRight;
SS.GW.projUp = projUp;
SS.chordTol = chordTol;
SS.GW.ZoomToFit(/*includingInvisibles=*/false);
SS.GenerateAll();
PaintGraphics();
framebuffer->WritePng(output, /*flip=*/true);
};
} else if(!strcmp(argv[1], "export-view")) {
for(size_t argn = 2; argn < argc; argn++) {
if(!(ParseInputFile(argn) ||
ParseOutputPattern(argn) ||
ParseViewDirection(argn) ||
ParseChordTolerance(argn))) {
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
return false;
}
}
if(EXACT(projUp.Magnitude() == 0 || projRight.Magnitude() == 0)) {
fprintf(stderr, "View direction must be specified.\n");
return false;
}
runner = [&](const std::string &output) {
SS.GW.projRight = projRight;
SS.GW.projUp = projUp;
SS.exportChordTol = chordTol;
SS.ExportViewOrWireframeTo(output, /*exportWireframe=*/false);
};
} else if(!strcmp(argv[1], "export-wireframe")) {
for(size_t argn = 2; argn < argc; argn++) {
if(!(ParseInputFile(argn) ||
ParseOutputPattern(argn) ||
ParseChordTolerance(argn))) {
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
return false;
}
}
runner = [&](const std::string &output) {
SS.exportChordTol = chordTol;
SS.ExportViewOrWireframeTo(output, /*exportWireframe=*/true);
};
} else if(!strcmp(argv[1], "export-mesh")) {
for(size_t argn = 2; argn < argc; argn++) {
if(!(ParseInputFile(argn) ||
ParseOutputPattern(argn) ||
ParseChordTolerance(argn))) {
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
return false;
}
}
runner = [&](const std::string &output) {
SS.exportChordTol = chordTol;
SS.ExportMeshTo(output);
};
} else if(!strcmp(argv[1], "export-surfaces")) {
for(size_t argn = 2; argn < argc; argn++) {
if(!(ParseInputFile(argn) ||
ParseOutputPattern(argn))) {
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
return false;
}
}
runner = [&](const std::string &output) {
StepFileWriter sfw = {};
sfw.ExportSurfacesTo(output);
};
} else {
fprintf(stderr, "Unrecognized command '%s'.\n", argv[1]);
return false;
}
if(outputPattern.empty()) {
fprintf(stderr, "An output pattern must be specified.\n");
return false;
} else if(outputPattern.find('%') == std::string::npos && inputFiles.size() > 1) {
fprintf(stderr,
"Output pattern must include a %% symbol when using multiple inputs!\n");
return false;
}
if(inputFiles.size() == 0) {
fprintf(stderr, "At least one input file must be specified.\n");
return false;
}
for(const std::string &inputFile : inputFiles) {
std::string outputFile = outputPattern;
size_t replaceAt = outputFile.find('%');
if(replaceAt != std::string::npos) {
outputFile.replace(replaceAt, 1, Basename(inputFile, /*stripExtension=*/true));
}
SS.Init();
if(!SS.LoadFromFile(inputFile)) {
fprintf(stderr, "Cannot load '%s'!\n", inputFile.c_str());
return false;
}
SS.AfterNewFile();
runner(outputFile);
SK.Clear();
SS.Clear();
fprintf(stderr, "Written '%s'.\n", outputFile.c_str());
}
return true;
}
int main(int argc, char **argv) {
InitPlatform();
if(argc == 1) {
ShowUsage(argv[0]);
return 0;
}
if(!RunCommand(argc, argv)) {
return 1;
} else {
return 0;
}
}

View File

@ -1,5 +1,5 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Our main() function for the headless (no OpenGL) test runner. // Our platform support functions for the headless (no OpenGL) test runner.
// //
// Copyright 2016 whitequark // Copyright 2016 whitequark
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -96,10 +96,8 @@ void ssremove(const std::string &filename)
static std::string ExpandPath(std::string path) { static std::string ExpandPath(std::string path) {
char *expanded_c_path = realpath(path.c_str(), NULL); char *expanded_c_path = realpath(path.c_str(), NULL);
if(expanded_c_path == NULL) { if(expanded_c_path == NULL) return "";
fprintf(stderr, "realpath(%s): %s\n", path.c_str(), strerror(errno));
return "";
}
std::string expanded_path = expanded_c_path; std::string expanded_path = expanded_c_path;
free(expanded_c_path); free(expanded_c_path);
return expanded_path; return expanded_path;

View File

@ -182,7 +182,7 @@ const FileFilter SlvsFileFilter[] = {
}; };
// PNG format bitmap // PNG format bitmap
const FileFilter PngFileFilter[] = { const FileFilter PngFileFilter[] = {
{ "PNG", { "png" } }, { "PNG file", { "png" } },
{ NULL, {} } { NULL, {} }
}; };
// Triangle mesh // Triangle mesh

View File

@ -57,19 +57,19 @@ set(testsuite_SOURCES
group/translate_nd/test.cpp group/translate_nd/test.cpp
) )
add_executable(solvespace_testsuite add_executable(solvespace-testsuite
${testsuite_SOURCES} ${testsuite_SOURCES}
$<TARGET_PROPERTY:resources,EXTRA_SOURCES>) $<TARGET_PROPERTY:resources,EXTRA_SOURCES>)
target_link_libraries(solvespace_testsuite target_link_libraries(solvespace-testsuite
solvespace_headless solvespace-headless
${COVERAGE_LIBRARY}) ${COVERAGE_LIBRARY})
add_dependencies(solvespace_testsuite add_dependencies(solvespace-testsuite
resources) resources)
add_custom_target(solvespace-test ALL add_custom_target(test_solvespace ALL
COMMAND $<TARGET_FILE:solvespace_testsuite> COMMAND $<TARGET_FILE:solvespace-testsuite>
COMMENT "Testing SolveSpace" COMMENT "Testing SolveSpace"
VERBATIM) VERBATIM)
@ -86,11 +86,11 @@ if(ENABLE_COVERAGE)
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/coverage_base.info OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/coverage_base.info
COMMAND ${LCOV} ${LCOV_FLAGS} ${LCOV_COLLECT} COMMAND ${LCOV} ${LCOV_FLAGS} ${LCOV_COLLECT}
-o ${CMAKE_BINARY_DIR}/coverage_base.info -i -o ${CMAKE_BINARY_DIR}/coverage_base.info -i
DEPENDS solvespace_testsuite DEPENDS solvespace-testsuite
COMMENT "Importing baseline coverage data" COMMENT "Importing baseline coverage data"
VERBATIM) VERBATIM)
add_custom_target(solvespace-coverage ALL add_custom_target(coverage_solvespace ALL
COMMAND ${LCOV} ${LCOV_FLAGS} ${LCOV_COLLECT} COMMAND ${LCOV} ${LCOV_FLAGS} ${LCOV_COLLECT}
-o ${CMAKE_BINARY_DIR}/coverage_test.info -o ${CMAKE_BINARY_DIR}/coverage_test.info
COMMAND ${LCOV} ${LCOV_FLAGS} COMMAND ${LCOV} ${LCOV_FLAGS}
@ -104,7 +104,7 @@ if(ENABLE_COVERAGE)
-o ${CMAKE_BINARY_DIR}/coverage/ -o ${CMAKE_BINARY_DIR}/coverage/
-t "SolveSpace testbench" -t "SolveSpace testbench"
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/coverage_base.info DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/coverage_base.info
DEPENDS solvespace-test DEPENDS test_solvespace
COMMENT "Generating coverage report" COMMENT "Generating coverage report"
VERBATIM) VERBATIM)
endif() endif()

View File

@ -1,7 +1,7 @@
#!/bin/sh -ex #!/bin/sh -ex
make -C build solvespace_testsuite make -C build solvespace-testsuite
./build/test/solvespace_testsuite $* || true ./build/test/solvespace-testsuite $* || true
for e in slvs png; do for e in slvs png; do
for i in `find . -name *.out.$e`; do for i in `find . -name *.out.$e`; do
mv $i `dirname $i`/`basename $i .out.$e`.$e; mv $i `dirname $i`/`basename $i .out.$e`.$e;

View File

@ -228,7 +228,7 @@ bool Test::Helper::CheckRender(const char *file, int line, const char *reference
std::shared_ptr<Pixmap> refPixmap = Pixmap::ReadPng(refPath.c_str(), /*flip=*/true); std::shared_ptr<Pixmap> refPixmap = Pixmap::ReadPng(refPath.c_str(), /*flip=*/true);
if(!RecordCheck(refPixmap && refPixmap->Equals(*framebuffer))) { if(!RecordCheck(refPixmap && refPixmap->Equals(*framebuffer))) {
framebuffer->WritePng(outPath.c_str(), /*flip=*/true); framebuffer->WritePng(outPath, /*flip=*/true);
if(!refPixmap) { if(!refPixmap) {
PrintFailure(file, line, "reference render not present"); PrintFailure(file, line, "reference render not present");