mirror of
https://github.com/schrodinger/pymol-open-source.git
synced 2026-06-03 19:54:24 +08:00
Added catch2 unit testing framework
This commit is contained in:
committed by
Thomas Holder
parent
6371955429
commit
d859e67b5b
1
INSTALL
1
INSTALL
@@ -21,6 +21,7 @@ REQUIREMENTS
|
||||
- mmtf-cpp (for fast MMTF export, disable with --use-msgpackc=no)
|
||||
- PyQt5, PyQt4, or PySide (optional, will fall back to Tk interface)
|
||||
- glm
|
||||
- catch2 (optional, enable with --testing)
|
||||
|
||||
SETUP OPTIONS
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ Z* -------------------------------------------------------------------
|
||||
|
||||
#include"os_python.h"
|
||||
|
||||
#include"PyMOLGlobals.h"
|
||||
#include"Base.h"
|
||||
#include"OVLexicon.h"
|
||||
|
||||
|
||||
@@ -115,6 +115,19 @@ static int run_only_once = true;
|
||||
#define API_SETUP_PYMOL_GLOBALS \
|
||||
G = _api_get_pymol_globals(self)
|
||||
|
||||
/*
|
||||
* C-level tests
|
||||
*/
|
||||
#ifdef _PYMOL_CTEST
|
||||
#include "TestCmdTest2.h"
|
||||
#else
|
||||
static PyObject* CmdTest2(PyObject*, PyObject*)
|
||||
{
|
||||
PyErr_SetString(PyExc_NotImplementedError, "compile with --testing");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Start a headless singleton instance in the current thread.
|
||||
*
|
||||
@@ -8685,6 +8698,7 @@ static PyMethodDef Cmd_methods[] = {
|
||||
{"symexp", CmdSymExp, METH_VARARGS},
|
||||
{"symmetry_copy", CmdSymmetryCopy, METH_VARARGS},
|
||||
{"test", CmdTest, METH_VARARGS},
|
||||
{"test2", CmdTest2, METH_VARARGS},
|
||||
{"toggle", CmdToggle, METH_VARARGS},
|
||||
{"matrix_copy", CmdMatrixCopy, METH_VARARGS},
|
||||
{"transform_object", CmdTransformObject, METH_VARARGS},
|
||||
|
||||
22
layerCTest/Test.cpp
Normal file
22
layerCTest/Test.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <iostream>
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
#include <catch2/catch.hpp>
|
||||
#include "Test.h"
|
||||
#include "TestCmdTest2.h"
|
||||
|
||||
using PyMOL_TestAPI = pymol::test::PYMOL_TEST_API;
|
||||
|
||||
PyObject *PyMOL_TestAPI::PYMOL_TEST_SUCCESS = PConvAutoNone(Py_None);
|
||||
PyObject *PyMOL_TestAPI::PYMOL_TEST_FAILURE = Py_BuildValue("i", -1);
|
||||
|
||||
PyObject *CmdTest2(PyObject *, PyObject *) {
|
||||
int argc = 1;
|
||||
char argv0[] = "pymol";
|
||||
char *argv[] = {argv0};
|
||||
auto result = Catch::Session().run(argc, argv);
|
||||
if (!result) {
|
||||
return PyMOL_TestAPI::PYMOL_TEST_SUCCESS;
|
||||
} else {
|
||||
return PyMOL_TestAPI::PYMOL_TEST_FAILURE;
|
||||
}
|
||||
}
|
||||
60
layerCTest/Test.h
Normal file
60
layerCTest/Test.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include "os_python.h"
|
||||
#include "PConv.h"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace pymol {
|
||||
namespace test {
|
||||
|
||||
// Checks whether obj is zero'd out (Struct of all PoD Types without non-default
|
||||
// values are 0)
|
||||
template <typename T> static bool isStructZero(const T &obj) {
|
||||
const auto size = sizeof(T);
|
||||
std::vector<char> buffer{size, 0};
|
||||
if (std::memcmp(buffer.data(), &obj, size)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Checks whether array arr is zeroed
|
||||
template <typename T>
|
||||
static bool isArrayZero(const T *arr, const std::size_t len) {
|
||||
auto bytelen = len * sizeof(T);
|
||||
std::vector<char> buffer(bytelen, 0);
|
||||
return std::memcmp(buffer.data(), arr, bytelen) == 0;
|
||||
}
|
||||
|
||||
// Checks whether arrays are equal
|
||||
template <typename T>
|
||||
static bool isArrayEqual(const T *arr1, const T *arr2, const std::size_t len) {
|
||||
return std::equal(arr1, arr1 + len, arr2);
|
||||
}
|
||||
|
||||
// Checks whether type has all special member functions
|
||||
template <typename T> static bool hasAllSpecialMemberFunctions()
|
||||
{
|
||||
return std::is_default_constructible<T>::value &&
|
||||
std::is_copy_constructible<T>::value &&
|
||||
std::is_copy_assignable<T>::value &&
|
||||
std::is_move_constructible<T>::value &&
|
||||
std::is_move_assignable<T>::value;
|
||||
}
|
||||
|
||||
// Checks whether ptr is equal to nullptr
|
||||
template <typename T> static bool isNullptr(const T *ptr) {
|
||||
return ptr == nullptr;
|
||||
}
|
||||
struct PYMOL_TEST_API {
|
||||
static PyObject *PYMOL_TEST_SUCCESS;
|
||||
static PyObject *PYMOL_TEST_FAILURE;
|
||||
};
|
||||
}; // namespace test
|
||||
}; // namespace pymol
|
||||
|
||||
3
layerCTest/TestCmdTest2.h
Normal file
3
layerCTest/TestCmdTest2.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "os_python.h"
|
||||
|
||||
PyObject *CmdTest2(PyObject *, PyObject *);
|
||||
10
layerCTest/Test_Classic_VLA.cpp
Normal file
10
layerCTest/Test_Classic_VLA.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "MemoryDebug.h"
|
||||
#include "Test.h"
|
||||
|
||||
TEST_CASE("VLA Classic Alloc", "[VLA_Classic]")
|
||||
{
|
||||
const std::size_t size = 10;
|
||||
auto ptr = VLACalloc(int, size);
|
||||
REQUIRE(pymol::test::isArrayZero(ptr, size));
|
||||
VLAFree(ptr);
|
||||
}
|
||||
180
layerCTest/Test_VLA.cpp
Normal file
180
layerCTest/Test_VLA.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
#include <array>
|
||||
#include "Test.h"
|
||||
#include "vla.h"
|
||||
|
||||
using namespace pymol::test;
|
||||
using pymol::vla;
|
||||
|
||||
TEST_CASE("VLA Default", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA;
|
||||
REQUIRE(isNullptr(myVLA.data()));
|
||||
}
|
||||
|
||||
TEST_CASE("VLA Alloc And Size", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA(5);
|
||||
REQUIRE(myVLA.size() == 5);
|
||||
}
|
||||
|
||||
TEST_CASE("VLA Default Val", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA(5, 0);
|
||||
REQUIRE(myVLA.size() == 5);
|
||||
REQUIRE(isArrayZero(myVLA.data(), myVLA.size()));
|
||||
}
|
||||
|
||||
TEST_CASE("VLA Initializer List", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA{1, 2, 3, 4, 5};
|
||||
const std::array<int, 5> myArr{1, 2, 3, 4, 5};
|
||||
REQUIRE(isArrayEqual(myVLA.data(), myArr.data(), myVLA.size()));
|
||||
}
|
||||
|
||||
TEST_CASE("VLA Special Member Functions", "[VLA]")
|
||||
{
|
||||
REQUIRE(hasAllSpecialMemberFunctions<vla<int>>());
|
||||
}
|
||||
|
||||
TEST_CASE("VLA Copy Construct", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA{1, 2, 3, 4, 5};
|
||||
auto copyVLA = myVLA;
|
||||
REQUIRE(myVLA.size() == copyVLA.size());
|
||||
REQUIRE(isArrayEqual(myVLA.data(), copyVLA.data(), myVLA.size()));
|
||||
}
|
||||
|
||||
TEST_CASE("VLA Copy Assign", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA{1, 2, 3, 4, 5};
|
||||
vla<int> copyVLA(1);
|
||||
REQUIRE(myVLA.size() != copyVLA.size());
|
||||
copyVLA = myVLA;
|
||||
REQUIRE(myVLA.size() == copyVLA.size());
|
||||
REQUIRE(isArrayEqual(myVLA.data(), copyVLA.data(), myVLA.size()));
|
||||
}
|
||||
|
||||
TEST_CASE("VLA Move Construct", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA{1, 2, 3, 4, 5};
|
||||
auto copyVLA = std::move(myVLA);
|
||||
REQUIRE(copyVLA.size() == 5);
|
||||
const std::array<int, 5> myArr{1, 2, 3, 4, 5};
|
||||
REQUIRE(isArrayEqual(copyVLA.data(), myArr.data(), copyVLA.size()));
|
||||
}
|
||||
|
||||
TEST_CASE("VLA Move Assign", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA{1, 2, 3, 4, 5};
|
||||
vla<int> copyVLA(3);
|
||||
copyVLA = std::move(myVLA);
|
||||
REQUIRE(copyVLA.size() == 5);
|
||||
const std::array<int, 5> myArr{1, 2, 3, 4, 5};
|
||||
REQUIRE(isArrayEqual(copyVLA.data(), myArr.data(), copyVLA.size()));
|
||||
}
|
||||
|
||||
TEST_CASE("Vector_Resize", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA(5);
|
||||
REQUIRE(myVLA.size() == 5);
|
||||
myVLA.resize(3);
|
||||
REQUIRE(myVLA.size() == 3);
|
||||
vla<int> myVLA2;
|
||||
myVLA2.resize(3);
|
||||
REQUIRE(myVLA2.size() == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("FreeP", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA(10);
|
||||
REQUIRE(myVLA.size() == 10);
|
||||
myVLA.freeP();
|
||||
REQUIRE(myVLA.size() == 0);
|
||||
REQUIRE(isNullptr(myVLA.data()));
|
||||
}
|
||||
|
||||
TEST_CASE("Bool Cast", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA;
|
||||
REQUIRE(myVLA == nullptr);
|
||||
vla<int> myVLA2(2);
|
||||
REQUIRE(myVLA2 != nullptr);
|
||||
myVLA2.freeP();
|
||||
REQUIRE(myVLA2 == nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE("Index", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA{1, 2, 3, 4, 5};
|
||||
REQUIRE(myVLA[2] == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("Range Based For", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA{0, 1, 2, 3, 4};
|
||||
std::size_t i{0u};
|
||||
for (auto& m : myVLA) {
|
||||
REQUIRE(myVLA[i] == i);
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
for (const auto& m : myVLA) {
|
||||
REQUIRE(myVLA[i] == i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("To_StdVector", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA{1, 2, 3, 4, 5};
|
||||
auto myStdVec = myVLA.toStdVector();
|
||||
REQUIRE(myStdVec.size() == myVLA.size());
|
||||
REQUIRE(isArrayEqual(myStdVec.data(), myVLA.data(), myStdVec.size()));
|
||||
}
|
||||
|
||||
TEST_CASE("From_StdVector", "[VLA]")
|
||||
{
|
||||
std::vector<int> myStdVec{1, 2, 3, 4, 5};
|
||||
vla<int> myVLA(myStdVec);
|
||||
REQUIRE(myStdVec.size() == myVLA.size());
|
||||
REQUIRE(isArrayEqual(myStdVec.data(), myVLA.data(), myStdVec.size()));
|
||||
}
|
||||
|
||||
TEST_CASE("From_VLACalloc", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA(VLACalloc(int, 5));
|
||||
REQUIRE(myVLA.size() == 5);
|
||||
REQUIRE(isArrayZero(myVLA.data(), 5));
|
||||
}
|
||||
|
||||
TEST_CASE("Classic_Copy", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA(5, 10);
|
||||
auto myVLACopy = VLACopy2(myVLA);
|
||||
REQUIRE(isArrayEqual(myVLA.data(), myVLACopy.data(), myVLA.size()));
|
||||
myVLACopy[1] = 100;
|
||||
REQUIRE(myVLA[1] != myVLACopy[1]);
|
||||
}
|
||||
|
||||
TEST_CASE("Classic_Check2", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA(5);
|
||||
VLACheck2(myVLA, 10);
|
||||
REQUIRE(myVLA.size() >= 11);
|
||||
}
|
||||
|
||||
TEST_CASE("Classic_Size2", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA(5);
|
||||
VLASize2(myVLA, 10);
|
||||
REQUIRE(myVLA.size() == 10);
|
||||
}
|
||||
|
||||
TEST_CASE("Classic_Free", "[VLA]")
|
||||
{
|
||||
vla<int> myVLA(5);
|
||||
VLAFreeP(myVLA);
|
||||
REQUIRE(isNullptr(myVLA.data()));
|
||||
}
|
||||
|
||||
// vi:sw=2:expandtab
|
||||
@@ -439,6 +439,8 @@ def launch(args=None, block_input_hook=0):
|
||||
if invocation.options.gui == 'pmg_qt':
|
||||
if invocation.options.no_gui:
|
||||
return _launch_no_gui()
|
||||
elif invocation.options.testing:
|
||||
return pymol._cmd.test2()
|
||||
|
||||
try:
|
||||
from pmg_qt import pymol_qt_gui
|
||||
|
||||
@@ -29,6 +29,7 @@ Options
|
||||
--version display PyMOL version and exit
|
||||
--retina use retina resolution (MacPyMOL) and set display_scale_factor=2
|
||||
--gldebug use glDebugMessageCallback for GL debugging
|
||||
--testing run pymol testing
|
||||
|
||||
-1 config_mouse one_button
|
||||
-2 config_mouse two_button
|
||||
@@ -170,6 +171,7 @@ if __name__=='pymol.invocation':
|
||||
options.no_spacenav = 0
|
||||
options.launch_status = 0
|
||||
options.gldebug = 0
|
||||
options.testing = 0
|
||||
|
||||
options.win_py = { 'irix':240,
|
||||
'darwin': 214, # hmm...need to set to 192 for Leopard?...
|
||||
@@ -281,6 +283,8 @@ if __name__=='pymol.invocation':
|
||||
print(' Warning: --nospnav not available in Open-Source PyMOL')
|
||||
elif a == "--gldebug":
|
||||
options.gldebug = 1
|
||||
elif a == "--testing":
|
||||
options.testing = 1
|
||||
else:
|
||||
# double hypen signals end of PyMOL arguments
|
||||
if python_script == None:
|
||||
|
||||
7
setup.py
7
setup.py
@@ -25,6 +25,7 @@ class options:
|
||||
no_glut = True
|
||||
use_msgpackc = 'guess'
|
||||
help_distutils = False
|
||||
testing = False
|
||||
|
||||
try:
|
||||
import argparse
|
||||
@@ -47,6 +48,8 @@ try:
|
||||
"shared library; no: disable fast MMTF load support")
|
||||
parser.add_argument('--help-distutils', action="store_true",
|
||||
help="show help for distutils options and exit")
|
||||
parser.add_argument('--testing', action="store_true",
|
||||
help="Build C-level tests")
|
||||
options, sys.argv[1:] = parser.parse_known_args(namespace=options)
|
||||
except ImportError:
|
||||
print("argparse not available")
|
||||
@@ -311,6 +314,10 @@ if options.no_glut:
|
||||
("_PYMOL_NO_MAIN", None),
|
||||
]
|
||||
|
||||
if options.testing:
|
||||
pymol_src_dirs += ["layerCTest"]
|
||||
def_macros += [("_PYMOL_CTEST", None)]
|
||||
|
||||
inc_dirs = list(pymol_src_dirs)
|
||||
|
||||
#============================================================================
|
||||
|
||||
Reference in New Issue
Block a user