diff --git a/docs/installation.rst b/docs/installation.rst
index b17cbbb..b2f011d 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -21,7 +21,6 @@ libraries are available to you:
* `GZIP `_ (gzip data compression)
* `LZMA `_ (lzma data compression)
* `CPPUnit `_ (unit testing)
-* `OpenSSL `_ (unit testing; MD5 checksums)
.. note::
* The instructions covered in this guide assume you are running a
@@ -33,8 +32,7 @@ libraries are available to you:
To ensure that all the packages are installed, one can run the following::
sudo apt install build-essential cmake libtclap-dev libboost-all-dev \
- pkg-config libcppunit-dev libeigen3-dev liblzma-dev zlib1g-dev libbz2-dev \
- libssl-dev
+ pkg-config libcppunit-dev libeigen3-dev liblzma-dev zlib1g-dev libbz2-dev
Standard compilation
--------------------
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
index 302fb99..60a0e72 100644
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -19,8 +19,6 @@
#*************************************************************************/
pkg_check_modules(CPPUNIT REQUIRED IMPORTED_TARGET cppunit)
-pkg_check_modules(CRYPTO REQUIRED IMPORTED_TARGET libcrypto)
-
add_library(unittest STATIC unittest.cpp)
target_compile_features(unittest PUBLIC cxx_std_17)
@@ -63,7 +61,6 @@ foreach(testexec ${EXECUTABLES})
unittest
den2objsources
PkgConfig::CPPUNIT
- PkgConfig::CRYPTO
)
add_test(NAME ${testexec} COMMAND ${testexec})
diff --git a/src/test/test_file_creation.cpp b/src/test/test_file_creation.cpp
index af15639..186694c 100644
--- a/src/test/test_file_creation.cpp
+++ b/src/test/test_file_creation.cpp
@@ -29,106 +29,134 @@ void TestFileCreation::tearDown() {
}
void TestFileCreation::test_ply_file() {
- // set number of threads to 1
- omp_set_num_threads(1);
-
- // read scalar field
- ScalarField sf("co_2pi_x.cub", ScalarFieldInputFileType::SFF_CUB);
- sf.read();
-
- // perform marching cubes algorithm
- IsoSurface is(&sf);
- is.marching_cubes(0.01);
-
- // construct mesh
- IsoSurfaceMesh ism(&sf, &is);
- ism.construct_mesh(true);
+ const auto ref = this->generate_mesh();
+ this->assert_ply_shape("test.ply", ref);
+}
- // create file
- ism.write_to_file("test.ply", "co molecule 2pi_x orbital test", "molecule");
+void TestFileCreation::test_stl_file() {
+ const auto ref = this->generate_mesh();
+ this->assert_stl_shape("test.stl", ref);
+}
- // test md5sum
- CPPUNIT_ASSERT_EQUAL(this->md5("test.ply"), std::string("ec143f6ebf9b72761803c3b091f54bf3"));
+void TestFileCreation::test_obj_file() {
+ const auto ref = this->generate_mesh();
+ this->assert_obj_shape("test.obj", ref);
}
-void TestFileCreation::test_stl_file() {
+TestFileCreation::MeshReference TestFileCreation::generate_mesh() const {
// set number of threads to 1
omp_set_num_threads(1);
// read scalar field
ScalarField sf("co_2pi_x.cub", ScalarFieldInputFileType::SFF_CUB);
sf.read();
-
+
// perform marching cubes algorithm
IsoSurface is(&sf);
is.marching_cubes(0.01);
-
+
// construct mesh
IsoSurfaceMesh ism(&sf, &is);
ism.construct_mesh(true);
- // create file
+ // create files for all supported output formats
+ ism.write_to_file("test.ply", "co molecule 2pi_x orbital test", "molecule");
ism.write_to_file("test.stl", "co molecule 2pi_x orbital test", "molecule");
+ ism.write_to_file("test.obj", "co molecule 2pi_x orbital test", "molecule");
- // test md5sum
- CPPUNIT_ASSERT_EQUAL(this->md5("test.stl"), std::string("c2194ba639caf5092654862bb9f93298"));
+ return {
+ ism.get_vertices().size(),
+ ism.get_normals().size(),
+ ism.get_texcoords().size() / 6
+ };
}
-void TestFileCreation::test_obj_file() {
- // set number of threads to 1
- omp_set_num_threads(1);
+void TestFileCreation::assert_obj_shape(const std::string& filename, const MeshReference& ref) const {
+ CPPUNIT_ASSERT(std::filesystem::exists(filename));
+
+ std::ifstream infile(filename);
+ CPPUNIT_ASSERT(infile.good());
+
+ std::string line;
+ size_t vertex_lines = 0;
+ size_t normal_lines = 0;
+ size_t face_lines = 0;
+
+ while(std::getline(infile, line)) {
+ if(line.rfind("v ", 0) == 0) {
+ vertex_lines++;
+ } else if(line.rfind("vn ", 0) == 0) {
+ normal_lines++;
+ } else if(line.rfind("f ", 0) == 0) {
+ face_lines++;
+ }
+ }
- // read scalar field
- ScalarField sf("co_2pi_x.cub", ScalarFieldInputFileType::SFF_CUB);
- sf.read();
-
- // perform marching cubes algorithm
- IsoSurface is(&sf);
- is.marching_cubes(0.01);
-
- // construct mesh
- IsoSurfaceMesh ism(&sf, &is);
- ism.construct_mesh(true);
+ CPPUNIT_ASSERT_EQUAL(ref.vertices, vertex_lines);
+ CPPUNIT_ASSERT_EQUAL(ref.normals, normal_lines);
+ CPPUNIT_ASSERT_EQUAL(ref.triangles, face_lines);
+}
- // create file
- ism.write_to_file("test.obj", "co molecule 2pi_x orbital test", "molecule");
+void TestFileCreation::assert_ply_shape(const std::string& filename, const MeshReference& ref) const {
+ CPPUNIT_ASSERT(std::filesystem::exists(filename));
+
+ std::ifstream infile(filename, std::ios::binary);
+ CPPUNIT_ASSERT(infile.good());
+
+ std::string line;
+ size_t header_size = 0;
+ size_t header_vertices = 0;
+ size_t header_faces = 0;
+ bool seen_ply = false;
+ bool seen_binary_format = false;
+
+ while(std::getline(infile, line)) {
+ header_size += line.size() + 1;
+
+ if(line == "ply") {
+ seen_ply = true;
+ }
+ if(line == "format binary_little_endian 1.0" || line == "format binary_big_endian 1.0") {
+ seen_binary_format = true;
+ }
+ if(line.rfind("element vertex ", 0) == 0) {
+ header_vertices = std::stoul(line.substr(15));
+ }
+ if(line.rfind("element face ", 0) == 0) {
+ header_faces = std::stoul(line.substr(13));
+ }
+ if(line == "end_header") {
+ break;
+ }
+ }
+
+ CPPUNIT_ASSERT(seen_ply);
+ CPPUNIT_ASSERT(seen_binary_format);
+ CPPUNIT_ASSERT_EQUAL(ref.vertices, header_vertices);
+ CPPUNIT_ASSERT_EQUAL(ref.triangles, header_faces);
- // test md5sum
- CPPUNIT_ASSERT_EQUAL(this->md5("test.obj"), std::string("e2b3e09f9c010dac99a7bc0137c187ec"));
+ const size_t expected_binary_size =
+ ref.vertices * (6 * sizeof(float)) +
+ ref.triangles * (sizeof(uint8_t) + 3 * sizeof(unsigned int));
+
+ CPPUNIT_ASSERT_EQUAL(header_size + expected_binary_size, (size_t)std::filesystem::file_size(filename));
}
-/**
- * @brief Calculate MD5 checksum of a file
- *
- * @param[in] name Path to the file
- *
- * @return 32 byte string containing md5 checksum
- */
-std::string TestFileCreation::md5(const std::string& filename) {
- // read the file
- std::ifstream mfile(filename, std::ios::binary | std::ios::ate);
- std::streamsize size = mfile.tellg();
- mfile.seekg(0, std::ios::beg);
- char buffer[size];
- mfile.read(buffer, size);
- mfile.close();
-
- // output variable for hash
- unsigned char hash[MD5_DIGEST_LENGTH];
-
- // calculate the md5 hash
- EVP_MD_CTX *ctx = EVP_MD_CTX_create();
- EVP_MD_CTX_init(ctx);
- const EVP_MD *md_type = EVP_md5();
- EVP_DigestInit_ex(ctx, md_type, NULL);
- EVP_DigestUpdate(ctx, buffer, size);
- EVP_DigestFinal_ex(ctx, hash, NULL);
- EVP_MD_CTX_destroy(ctx);
-
- // output as a 32-byte hex-string
- std::stringstream ss;
- for(int i = 0; i < MD5_DIGEST_LENGTH; i++){
- ss << std::hex << std::setw(2) << std::setfill('0') << static_cast( hash[i] );
- }
- return ss.str();
-}
\ No newline at end of file
+void TestFileCreation::assert_stl_shape(const std::string& filename, const MeshReference& ref) const {
+ CPPUNIT_ASSERT(std::filesystem::exists(filename));
+
+ std::ifstream infile(filename, std::ios::binary);
+ CPPUNIT_ASSERT(infile.good());
+
+ // skip header
+ infile.seekg(80, std::ios::beg);
+
+ uint32_t triangle_count = 0;
+ infile.read(reinterpret_cast(&triangle_count), sizeof(uint32_t));
+ CPPUNIT_ASSERT(infile.good());
+
+ CPPUNIT_ASSERT_EQUAL(static_cast(ref.triangles), triangle_count);
+
+ const size_t expected_size = 80 + sizeof(uint32_t) + ref.triangles * (12 * sizeof(float) + sizeof(uint16_t));
+ CPPUNIT_ASSERT_EQUAL(expected_size, (size_t)std::filesystem::file_size(filename));
+}
diff --git a/src/test/test_file_creation.h b/src/test/test_file_creation.h
index 3615fd2..744ab0f 100644
--- a/src/test/test_file_creation.h
+++ b/src/test/test_file_creation.h
@@ -23,10 +23,9 @@
#include
-// we need these for the MD5 checksums
-#include
-#include
-#include
+#include
+#include
+#include
#include "scalar_field.h"
#include "isosurface.h"
@@ -34,12 +33,11 @@
/**
* Test that verifies file creation (obj, stl and ply)
- *
+ *
* Because the marching cubes algorithm uses OpenMP parallellization, we need
* to set the number of threads to 1 to obtain consistent results. With
* higher number of cores, the results are subject to race conditions, leading
- * to different (although not incorrect) results preventing the use of a simple
- * MD5 checksum for file validation.
+ * to different (although not incorrect) results.
*/
class TestFileCreation : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE( TestFileCreation );
@@ -56,7 +54,16 @@ class TestFileCreation : public CppUnit::TestFixture {
void tearDown();
private:
- std::string md5(const std::string &str);
+ struct MeshReference {
+ size_t vertices;
+ size_t normals;
+ size_t triangles;
+ };
+
+ MeshReference generate_mesh() const;
+ void assert_obj_shape(const std::string& filename, const MeshReference& ref) const;
+ void assert_ply_shape(const std::string& filename, const MeshReference& ref) const;
+ void assert_stl_shape(const std::string& filename, const MeshReference& ref) const;
};
-#endif
\ No newline at end of file
+#endif