Files
dssp/test/unit-test-dssp.cpp
Maarten L. Hekkelman 5187ff7355 Add minimal components.cif
2026-04-14 11:50:24 +02:00

287 lines
7.7 KiB
C++

/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define CATCH_CONFIG_RUNNER
#include "../libdssp/src/dssp-io.hpp"
#include "../src/revision.hpp"
#include "dssp.hpp"
#include <catch2/catch_all.hpp>
#include <cif++/dictionary_parser.hpp>
namespace fs = std::filesystem;
// --------------------------------------------------------------------
cif::file operator""_cf(const char *text, size_t length)
{
struct membuf : public std::streambuf
{
membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} buffer(const_cast<char *>(text), length);
std::istream is(&buffer);
return cif::file(is);
}
// --------------------------------------------------------------------
std::filesystem::path gTestDir;
int main(int argc, char *argv[])
{
gTestDir = std::filesystem::current_path();
Catch::Session session; // There must be exactly one instance
// Build a new parser on top of Catch2's
using namespace Catch::Clara;
std::filesystem::path rsrc_dir;
auto cli = session.cli() // Get Catch2's command line parser
| Opt(gTestDir, "data-dir") // bind variable to a new option, with a hint string
["-D"]["--data-dir"] // the option names it will respond to
| Opt(rsrc_dir, "rsrc-dir") // bind variable to a new option, with a hint string
["-D"]["--rsrc-dir"] // the option names it will respond to
("The directory containing the data files"); // description string for the help output
// Now pass the new composite back to Catch2 so it uses that
session.cli(cli);
// Let Catch2 (using Clara) parse the command line
int returnCode = session.applyCommandLine(argc, argv);
if (returnCode != 0) // Indicates a command line error
return returnCode;
if (not rsrc_dir.empty() and std::filesystem::exists(rsrc_dir))
cif::add_data_directory(rsrc_dir);
cif::add_data_directory(gTestDir / "libdssp" / "mmcif_pdbx");
cif::add_file_resource("components.cif", gTestDir / "minimal-components.cif");
return session.run();
}
// --------------------------------------------------------------------
TEST_CASE("ut_dssp")
{
using namespace std::literals;
auto f = cif::pdb::read(gTestDir / "1cbs.cif.gz");
REQUIRE(f.is_valid());
dssp dssp(f.front(), 1, 3, true);
std::stringstream test;
writeDSSP(dssp, test);
std::ifstream reference(gTestDir / "1cbs.dssp");
CHECK(reference.is_open());
std::string line_t, line_r;
CHECK((std::getline(test, line_t) and std::getline(reference, line_r)));
char kHeaderLineStart[] = "==== Secondary Structure Definition by the program DSSP, NKI version 4.5.4 ====";
memcpy(kHeaderLineStart + 69, kVersionNumber, strlen(kVersionNumber));
CHECK(line_t.compare(0, std::strlen(kHeaderLineStart), kHeaderLineStart) == 0);
// CHECK(line_r.compare(0, std::strlen(kHeaderLineStart), kHeaderLineStart) == 0);
for (int line_nr = 2;; ++line_nr)
{
bool done_t = not std::getline(test, line_t);
bool done_r = not std::getline(reference, line_r);
CHECK(done_r == done_t);
if (done_r)
break;
if (line_t != line_r)
{
if (cif::starts_with(line_t, "REFERENCE ") and cif::starts_with(line_r, "REFERENCE "))
continue;
// std::cerr << line_nr << '\n'
// << line_t << '\n'
// << line_r << '\n';
}
REQUIRE(line_t == line_r);
}
CHECK(test.eof());
CHECK(reference.eof());
}
TEST_CASE("ut_mmcif_2")
{
using namespace std::literals;
using namespace cif::literals;
auto f = cif::pdb::read(gTestDir / "1cbs.cif.gz");
REQUIRE(f.is_valid());
dssp dssp(f.front(), 1, 3, true);
dssp.annotate(f.front(), true, true);
cif::file rf(gTestDir / "1cbs-dssp.cif");
auto &db1 = f.front();
auto &db2 = rf.front();
db1["software"].erase("name"_key == "DSSP");
std::erase_if(db1, [](cif::category &cat)
{ return cat.name() == "audit_conform"; });
db2["software"].erase("name"_key == "DSSP");
std::erase_if(db2, [](cif::category &cat)
{ return cat.name() == "audit_conform"; });
if (not (f.front() == rf.front()))
{
// std::ofstream a(std::filesystem::temp_directory_path() / "dssp-test-a.cif");
// a << f.front();
// a.close();
// std::ofstream b(std::filesystem::temp_directory_path() / "dssp-test-b.cif");
// b << rf.front();
// b.close();
CHECK(false);
}
}
// --------------------------------------------------------------------
TEST_CASE("dssp_1")
{
auto f = cif::pdb::read(gTestDir / "1cbs.cif.gz");
REQUIRE(f.is_valid());
std::ifstream t(gTestDir / "1cbs-dssp-test.tsv");
dssp dssp(f.front(), 1, 3, true);
for (auto residue : dssp)
{
std::string line;
getline(t, line);
// std::cout << line << '\n';
auto fld = cif::split(line, "\t");
CHECK(fld.size() == 3);
if (fld.size() != 3)
continue;
int seqID;
std::from_chars(fld[0].data(), fld[0].data() + fld[0].length(), seqID);
std::string asymID{ fld[1] };
std::string secstr{ fld[2] };
if (secstr == "_")
secstr = " ";
CHECK(residue.asym_id() == asymID);
CHECK(residue.seq_id() == seqID);
CHECK((char)residue.type() == secstr.front());
}
}
// --------------------------------------------------------------------
TEST_CASE("dssp_2")
{
auto f = cif::pdb::read(gTestDir / "1cbs.cif.gz");
REQUIRE(f.is_valid());
dssp dssp(f.front(), 1, 3, true);
std::ifstream t(gTestDir / "1cbs-dssp-test.tsv");
std::string line;
while (getline(t, line))
{
auto fld = cif::split(line, "\t");
CHECK(fld.size() == 3);
if (fld.size() != 3)
continue;
int seqID;
std::from_chars(fld[0].data(), fld[0].data() + fld[0].length(), seqID);
std::string asymID{ fld[1] };
std::string secstr{ fld[2] };
if (secstr == "_")
secstr = " ";
dssp::key_type key{ asymID, seqID };
auto ri = dssp[key];
CHECK(ri.asym_id() == asymID);
CHECK(ri.seq_id() == seqID);
CHECK((char)ri.type() == secstr.front());
}
}
// --------------------------------------------------------------------
TEST_CASE("dssp_3")
{
auto f = cif::pdb::read(gTestDir / "1cbs.cif.gz");
REQUIRE(f.is_valid());
dssp dssp(f.front(), 1, 3, true);
dssp.annotate(f.front(), true, true);
// CHECK(f.is_valid());
}
// --------------------------------------------------------------------
TEST_CASE("dssp_pdb")
{
auto f = cif::pdb::read(gTestDir / "pdb1cbs.ent.gz");
REQUIRE(f.is_valid());
dssp dssp(f.front(), 1, 3, true);
dssp.annotate(f.front(), true, true);
}