Files
libcifpp/test/validate-pdbx-test.cpp
2026-02-18 15:10:12 +01:00

299 lines
7.4 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.
*/
#include "test-main.hpp"
#include <cif++/cif++.hpp>
#include <stdexcept>
// --------------------------------------------------------------------
cif::file operator""_cf(const char *text, std::size_t length)
{
struct membuf : public std::streambuf
{
membuf(char *text, std::size_t length)
{
this->setg(text, text, text + length);
}
} buffer(const_cast<char *>(text), length);
std::istream is(&buffer);
return cif::file(is);
}
// --------------------------------------------------------------------
TEST_CASE("test-1")
{
auto f = R"(data_1CBS
#
_entry.id 1CBS
#
_entity.id 1
_entity.type polymer
#
_entity_poly.entity_id 1
_entity_poly.type 'polypeptide(L)'
_entity_poly.nstd_linkage no
_entity_poly.nstd_monomer no
_entity_poly.pdbx_seq_one_letter_code
;PNFSG
;
_entity_poly.pdbx_seq_one_letter_code_can
;PNFSG
;
_entity_poly.pdbx_strand_id A
_entity_poly.pdbx_target_identifier ?
#
loop_
_entity_poly_seq.entity_id
_entity_poly_seq.num
_entity_poly_seq.mon_id
_entity_poly_seq.hetero
1 1 PRO n
1 2 ASN n
1 3 PHE n
1 4 SER n
1 5 GLY n
#
loop_
_struct_asym.id
_struct_asym.pdbx_blank_PDB_chainid_flag
_struct_asym.pdbx_modified
_struct_asym.entity_id
_struct_asym.details
A N N 1 ?
#
loop_
_atom_type.symbol
C
N
O
S
#
loop_
_atom_site.group_PDB
_atom_site.id
_atom_site.type_symbol
_atom_site.label_atom_id
_atom_site.label_alt_id
_atom_site.label_comp_id
_atom_site.label_asym_id
_atom_site.label_entity_id
_atom_site.label_seq_id
_atom_site.pdbx_PDB_ins_code
_atom_site.Cartn_x
_atom_site.Cartn_y
_atom_site.Cartn_z
_atom_site.occupancy
_atom_site.B_iso_or_equiv
_atom_site.pdbx_formal_charge
_atom_site.auth_seq_id
_atom_site.auth_comp_id
_atom_site.auth_asym_id
_atom_site.auth_atom_id
_atom_site.pdbx_PDB_model_num
ATOM 2 C CA . PRO A 1 1 ? 18.150 13.525 43.680 1.00 28.82 ? 1 PRO A CA 1
ATOM 9 C CA . ASN A 1 2 ? 20.576 16.457 43.578 1.00 20.79 ? 2 ASN A CA 1
ATOM 17 C CA . PHE A 1 3 ? 21.144 17.838 40.087 1.00 12.62 ? 3 PHE A CA 1
ATOM 28 C CA . SER A 1 4 ? 23.170 20.780 41.464 1.00 11.30 ? 4 SER A CA 1
ATOM 34 C CA . GLY A 1 5 ? 26.628 21.486 40.103 1.00 10.86 ? 5 GLY A CA 1
#
loop_
_pdbx_poly_seq_scheme.asym_id
_pdbx_poly_seq_scheme.entity_id
_pdbx_poly_seq_scheme.seq_id
_pdbx_poly_seq_scheme.mon_id
_pdbx_poly_seq_scheme.ndb_seq_num
_pdbx_poly_seq_scheme.pdb_seq_num
_pdbx_poly_seq_scheme.auth_seq_num
_pdbx_poly_seq_scheme.pdb_mon_id
_pdbx_poly_seq_scheme.auth_mon_id
_pdbx_poly_seq_scheme.pdb_strand_id
_pdbx_poly_seq_scheme.pdb_ins_code
_pdbx_poly_seq_scheme.hetero
A 1 1 PRO 1 1 1 PRO PRO A . n
A 1 2 ASN 2 2 2 ASN ASN A . n
A 1 3 PHE 3 3 3 PHE PHE A . n
A 1 4 SER 4 4 4 SER SER A . n
A 1 5 GLY 5 5 5 GLY GLY A . n
#
)"_cf;
SECTION("Plain file")
{
REQUIRE(cif::pdb::is_valid_pdbx_file(f));
}
SECTION("Delete one atom_site")
{
auto &db = f.front();
auto n = db["atom_site"].erase(cif::key("id") == 2);
REQUIRE(n == 1);
REQUIRE(cif::pdb::is_valid_pdbx_file(f));
}
SECTION("Delete a pdbx_poly_seq_scheme record")
{
auto &db = f.front();
auto n = db["pdbx_poly_seq_scheme"].erase(cif::key("seq_id") == 2);
REQUIRE(n == 1);
REQUIRE_FALSE(cif::pdb::is_valid_pdbx_file(f));
}
SECTION("Delete an entity_poly_seq record")
{
auto &db = f.front();
auto n = db["entity_poly_seq"].erase(cif::key("num") == 2);
REQUIRE(n == 1);
REQUIRE_FALSE(cif::pdb::is_valid_pdbx_file(f));
}
SECTION("Delete an entity_poly record")
{
auto &db = f.front();
auto n = db["entity_poly"].erase(cif::key("entity_id") == 1);
REQUIRE(n == 1);
REQUIRE_FALSE(cif::pdb::is_valid_pdbx_file(f));
}
SECTION("Mutate an atom_site record")
{
auto &db = f.front();
auto r = db["atom_site"].find1(cif::key("id") == 9);
r.assign({
{ "label_comp_id", "ALA" },
{ "auth_comp_id", "ALA" }
});
REQUIRE_FALSE(cif::pdb::is_valid_pdbx_file(f));
}
SECTION("Hetero consistency")
{
auto &db = f.front();
db["entity_poly_seq"].emplace({ //
{ "entity_id", 1 },
{ "num", 1 },
{ "mon_id", "ALA" },
{ "hetero", "n" }
});
db["pdbx_poly_seq_scheme"].emplace({ //
{ "asym_id", "A" },
{ "entity_id", "1" },
{ "seq_id", "1" },
{ "mon_id", "ALA" },
{ "ndb_seq_num", 1 },
{ "pdb_seq_num", "1" },
{ "auth_seq_num", "1" },
{ "pdb_mon_id", "ALA" },
{ "auth_mon_id", "ALA" },
{ "pdb_strand_id", "A" },
{ "pdb_ins_code", "." },
{ "hetero", "n" }
});
REQUIRE_FALSE(cif::pdb::is_valid_pdbx_file(f));
}
SECTION("Missing hetero for record in atom_site")
{
auto &db = f.front();
auto r1 = db["atom_site"].front();
cif::row_initializer cr(r1);
cr.set_value("id", "3");
cr.set_value("label_comp_id", "ALA");
db["atom_site"].emplace(std::move(cr));
REQUIRE_FALSE(cif::pdb::is_valid_pdbx_file(f));
}
SECTION("Missing letter in entity_poly.pdbx_seq_one_letter_code")
{
auto &db = f.front();
auto &entity_poly = db["entity_poly"];
entity_poly.front().assign({
{ "pdbx_seq_one_letter_code", "PNSG" }
});
REQUIRE_FALSE(cif::pdb::is_valid_pdbx_file(f));
}
SECTION("Too many letters in entity_poly.pdbx_seq_one_letter_code")
{
auto &db = f.front();
auto &entity_poly = db["entity_poly"];
entity_poly.front().assign({
{ "pdbx_seq_one_letter_code", "PNFSGX" }
});
REQUIRE_FALSE(cif::pdb::is_valid_pdbx_file(f));
}
SECTION("Mismatch in entity_poly.pdbx_seq_one_letter_code")
{
auto &db = f.front();
auto &entity_poly = db["entity_poly"];
entity_poly.front().assign({
{ "pdbx_seq_one_letter_code", "PNASG" }
});
REQUIRE_FALSE(cif::pdb::is_valid_pdbx_file(f));
}
}
TEST_CASE("extended-dictionary-1")
{
cif::add_file_resource("dssp-extension.dic", gTestDir / "dssp-extension.dic");
cif::VERBOSE = 2;
auto f = cif::pdb::read(gTestDir / "1cbs-dssp.cif");
CHECK(f.is_valid());
}
TEST_CASE("brak")
{
auto f = cif::pdb::read(gTestDir / "brak.pdb");
CHECK(f.is_valid());
}