mirror of
https://github.com/PDB-REDO/libcifpp.git
synced 2026-06-04 13:54:25 +08:00
3669 lines
82 KiB
C++
3669 lines
82 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 "cif++/category.hpp"
|
|
#include "cif++/model.hpp"
|
|
#include "cif++/row.hpp"
|
|
#include "test-main.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <catch2/catch_test_macros.hpp>
|
|
#include <cif++/cif++.hpp>
|
|
#include <exception>
|
|
#include <ostream>
|
|
#include <sstream>
|
|
#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("text_1")
|
|
{
|
|
CHECK(cif::iequals("TEST", "test"));
|
|
CHECK(cif::iequals(std::string_view{ "TEST" }, std::string_view{ "test" }));
|
|
|
|
CHECK(cif::icompare("TEST", "test") == 0);
|
|
CHECK(cif::icompare(std::string_view{ "TEST" }, std::string_view{ "test" }) == 0);
|
|
|
|
CHECK(cif::icompare("TEST1", "test") > 0);
|
|
CHECK(cif::icompare(std::string_view{ "TEST1" }, std::string_view{ "test" }) > 0);
|
|
|
|
CHECK(cif::icompare("aap", "noot") < 0);
|
|
CHECK(cif::icompare(std::string_view{ "aap" }, std::string_view{ "noot" }) < 0);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("text_2")
|
|
{
|
|
// Test based on https://www.iucr.org/resources/cif/spec/version1.1/semantics
|
|
|
|
// There is a problem with this specification though, the fourth example
|
|
// as given on the website consists of three lines, the first being blank.
|
|
|
|
auto f = R"(
|
|
#\
|
|
data_X
|
|
|
|
# Here is another example of folding. The following three text fields would be equivalent:
|
|
loop_
|
|
_cat.f1
|
|
;C:\foldername\filename
|
|
;
|
|
|
|
;\
|
|
C:\foldername\filename
|
|
;
|
|
|
|
;\
|
|
C:\foldername\file\
|
|
name
|
|
;
|
|
|
|
# but the next example would be a two-line value where the first line had the value "C:\foldername\file\" and the second had the value "name":
|
|
|
|
;
|
|
C:\foldername\file\
|
|
name
|
|
;
|
|
)"_cf;
|
|
|
|
auto &db = f.front();
|
|
auto &cat = db["cat"];
|
|
for (size_t ix = 0; std::string v : cat.rows<std::string>("f1"))
|
|
{
|
|
if (++ix == 4)
|
|
CHECK(v == R"(
|
|
C:\foldername\file\
|
|
name)");
|
|
else
|
|
CHECK(v == R"(C:\foldername\filename)");
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("from_chars_1")
|
|
{
|
|
auto f = R"(data_TEST
|
|
#
|
|
loop_
|
|
_test.v
|
|
616.487
|
|
616.487000
|
|
)"_cf;
|
|
|
|
auto &db = f.front();
|
|
auto &c = db.front();
|
|
|
|
auto r1 = c.front();
|
|
CHECK(r1.get<double>("v") == 616.487);
|
|
CHECK(r1["v"].compare(616.487) == 0);
|
|
|
|
auto r2 = c.back();
|
|
CHECK(r2.get<double>("v") == 616.487);
|
|
CHECK(r2["v"].compare(616.487) == 0);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("id_1")
|
|
{
|
|
CHECK(cif::cif_id_for_number(0) == "A");
|
|
CHECK(cif::cif_id_for_number(25) == "Z");
|
|
CHECK(cif::cif_id_for_number(26) == "AA");
|
|
CHECK(cif::cif_id_for_number(26 + 1) == "AB");
|
|
|
|
CHECK(cif::cif_id_for_number(26 + 26 * 26 - 1) == "ZZ");
|
|
CHECK(cif::cif_id_for_number(26 + 26 * 26) == "AAA");
|
|
CHECK(cif::cif_id_for_number(26 + 26 * 26 + 1) == "AAB");
|
|
|
|
std::set<std::string> testset;
|
|
|
|
for (int i = 0; i < 100000; ++i)
|
|
{
|
|
std::string id = cif::cif_id_for_number(i);
|
|
CHECK(testset.count(id) == 0);
|
|
testset.insert(id);
|
|
}
|
|
CHECK(testset.size() == 100000);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("cc_1")
|
|
{
|
|
std::tuple<std::string_view, float, char> tests[] = {
|
|
{ "1.0", 1.0f, 0 },
|
|
{ "1.0e10", 1.0e10f, 0 },
|
|
{ "-1.1e10", -1.1e10f, 0 },
|
|
{ "-.2e11", -.2e11f, 0 },
|
|
{ "1.3e-10", 1.3e-10f, 0 },
|
|
|
|
{ "1.0 ", 1.0f, ' ' },
|
|
{ "1.0e10 ", 1.0e10f, ' ' },
|
|
{ "-1.1e10 ", -1.1e10f, ' ' },
|
|
{ "-.2e11 ", -.2e11f, ' ' },
|
|
{ "1.3e-10 ", 1.3e-10f, ' ' },
|
|
|
|
{ "3.0", 3.0f, 0 },
|
|
{ "3.0 ", 3.0f, ' ' },
|
|
|
|
{ "3.000000", 3.0f, 0 },
|
|
{ "3.000000 ", 3.0f, ' ' },
|
|
};
|
|
|
|
for (const auto &[txt, val, ch] : tests)
|
|
{
|
|
float tv;
|
|
const auto &[ptr, ec] = cif::from_chars(txt.data(), txt.data() + txt.length(), tv);
|
|
|
|
CHECK(ec == std::errc{});
|
|
CHECK(tv == val);
|
|
if (ch != 0)
|
|
CHECK(*ptr == ch);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("cc_2")
|
|
{
|
|
std::tuple<float, int, std::string_view> tests[] = {
|
|
{ 1.1f, 1, "1.1" }
|
|
};
|
|
|
|
for (const auto &[val, prec, test] : tests)
|
|
{
|
|
char buffer[64] = {};
|
|
const auto &[ptr, ec] = std::to_chars(buffer, buffer + sizeof(buffer), val, std::chars_format::fixed, prec);
|
|
|
|
CHECK(ec == std::errc{});
|
|
|
|
// This line generates a linker error on Windows:
|
|
// CHECK(buffer == test);
|
|
CHECK(std::string{ buffer } == std::string{ test });
|
|
}
|
|
}
|
|
|
|
TEST_CASE("item_0")
|
|
{
|
|
cif::item i1("v1", "tekst");
|
|
cif::item i2("v2", 2);
|
|
cif::item i3("v3", { 3.0, 2 });
|
|
// cif::item i4("v4", true);
|
|
cif::item i5("v5", nullptr);
|
|
|
|
static_assert(cif::IntegralType<int>);
|
|
static_assert(cif::FloatType<double>);
|
|
|
|
CHECK(i1.value().get<std::string>() == "tekst");
|
|
CHECK(i2.value().get<int>() == 2);
|
|
CHECK(i3.value().get<double>() == 3.0);
|
|
CHECK(i3.value().str() == "3.00");
|
|
// CHECK(i4.value().get<bool>() == true);
|
|
CHECK(i5.value().is_null());
|
|
CHECK(i5.value().is_missing());
|
|
CHECK(i5.value().empty());
|
|
|
|
i2.value() = false;
|
|
CHECK(i2.value().type() == cif::item_value_type::INT);
|
|
// CHECK(i2.value().get<bool>() == false);
|
|
|
|
cif::item i6 = std::move(i1);
|
|
CHECK(i6.value().get<std::string>() == "tekst");
|
|
CHECK(i1.value().is_null()); // NOLINT
|
|
}
|
|
|
|
// TEST_CASE("row_1")
|
|
// {
|
|
// cif::row r;
|
|
|
|
// r.append(0, 1);
|
|
// r.append(1, "twee");
|
|
|
|
// cif::category cat("cat");
|
|
|
|
// cat.add_item("een");
|
|
// cat.add_item("twee");
|
|
|
|
// cif::row_handle rh(cat, r);
|
|
|
|
// const auto &[a, b] = rh.get<int, std::string>("een", "twee");
|
|
// CHECK(a == 1);
|
|
// CHECK(b == "twee");
|
|
|
|
// rh.assign("twee", 3.0, false);
|
|
// CHECK(rh[1].type() == cif::item_value_type::FLOAT);
|
|
// CHECK(rh[1].get<double>() == 3.0);
|
|
// }
|
|
|
|
TEST_CASE("cc_3")
|
|
{
|
|
cif::category c("foo");
|
|
c.emplace({
|
|
{ "f-1", 1 },
|
|
{ "f-2", "-1" },
|
|
{ "f-3", "+1" },
|
|
{ "f-4", " 1" },
|
|
{ "f-5", " +1" },
|
|
{ "f-6", "1 " },
|
|
});
|
|
|
|
auto row = c.front();
|
|
CHECK(row["f-1"].get<int>() == 1);
|
|
CHECK(row["f-2"].get<int>() == -1);
|
|
|
|
CHECK_FALSE(row["f-3"].is_number());
|
|
CHECK_FALSE(row["f-4"].is_number());
|
|
CHECK_FALSE(row["f-5"].is_number());
|
|
CHECK_FALSE(row["f-6"].is_number());
|
|
}
|
|
|
|
TEST_CASE("item_1")
|
|
{
|
|
using namespace cif;
|
|
|
|
item i1("1", "1");
|
|
item i2("2", 2.0f);
|
|
item i3("3", '3');
|
|
|
|
item ci1(i1);
|
|
item ci2(i2);
|
|
item ci3(i3);
|
|
|
|
CHECK(i1.value() == ci1.value());
|
|
CHECK(i2.value() == ci2.value());
|
|
CHECK(i3.value() == ci3.value());
|
|
|
|
item mi1(std::move(ci1));
|
|
item mi2(std::move(ci2));
|
|
item mi3(std::move(ci3));
|
|
|
|
CHECK(i1.value() == mi1.value());
|
|
CHECK(i2.value() == mi2.value());
|
|
CHECK(i3.value() == mi3.value());
|
|
|
|
// NOLINTBEGIN(bugprone-use-after-move)
|
|
CHECK(ci1.empty());
|
|
CHECK(ci2.empty());
|
|
CHECK(ci3.empty());
|
|
// NOLINTEND(bugprone-use-after-move)
|
|
}
|
|
|
|
TEST_CASE("item_2")
|
|
{
|
|
using namespace cif;
|
|
|
|
cif::item i0("test1");
|
|
CHECK(i0.value().empty());
|
|
CHECK(i0.value().type() == cif::item_value_type::MISSING);
|
|
|
|
cif::item i1("test1", std::optional<float>());
|
|
CHECK(i0.value().empty());
|
|
// CHECK(i1.value() == "?");
|
|
|
|
cif::item i2("test1", std::make_optional<float>(1.f));
|
|
CHECK(i2.value() == 1.0f);
|
|
|
|
// TODO: revive/fix
|
|
// cif::item i3("test1", { std::optional<float>(), 2 });
|
|
// CHECK(i3.value() == "?");
|
|
|
|
// cif::item i4("test1", { std::make_optional<float>(1.f), 2 });
|
|
// CHECK(i4.value() == "1.00");
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("r_1")
|
|
{
|
|
cif::category c("foo");
|
|
c.emplace({
|
|
{ "f-1", 1 },
|
|
{ "f-2", "two" },
|
|
{ "f-3", 3.0f /* , 3 */ },
|
|
});
|
|
|
|
auto row = c.front();
|
|
// CHECK(row["f-1"].compare(1) == 0);
|
|
// CHECK(row["f-2"].compare("two") == 0);
|
|
// CHECK(row["f-3"].compare(3.0f) == 0); // This fails when running in valgrind... sigh
|
|
|
|
const auto &[f1, f2, f3] = row.get<int, std::string, float>("f-1", "f-2", "f-3");
|
|
|
|
CHECK(f1 == 1);
|
|
CHECK(f2 == "two");
|
|
CHECK(f3 == 3.0f); // This fails when running in valgrind... sigh
|
|
|
|
CHECK(row.get<int>("f-1") == 1);
|
|
CHECK(row.get<std::string>("f-2") == "two");
|
|
CHECK(row.get<float>("f-3") == 3.0f);
|
|
|
|
int f_1;
|
|
std::string f_2;
|
|
float f_3;
|
|
|
|
cif::tie(f_1, f_2, f_3) = row.get("f-1", "f-2", "f-3");
|
|
|
|
CHECK(f_1 == 1);
|
|
CHECK(f_2 == "two");
|
|
CHECK(f_3 == 3.0f); // This fails when running in valgrind... sigh
|
|
}
|
|
|
|
TEST_CASE("r_2")
|
|
{
|
|
cif::category c("foo");
|
|
|
|
for (std::size_t i = 1; i < 256; ++i)
|
|
{
|
|
c.emplace({ { "id", i },
|
|
{ "txt", std::string(i, 'x') } });
|
|
}
|
|
}
|
|
|
|
TEST_CASE("c_1")
|
|
{
|
|
cif::category c("foo");
|
|
|
|
c.emplace({ { "id", 1 }, { "s", "aap" } });
|
|
c.emplace({ { "id", 2 }, { "s", "noot" } });
|
|
c.emplace({ { "id", 3 }, { "s", "mies" } });
|
|
|
|
int n = 1;
|
|
|
|
const char *ts[] = { "aap", "noot", "mies" };
|
|
|
|
for (auto r : c)
|
|
{
|
|
CHECK(r["id"].get<int>() == n);
|
|
CHECK(r["s"].compare(ts[n - 1]) == 0);
|
|
++n;
|
|
}
|
|
|
|
n = 1;
|
|
|
|
for (auto r : c)
|
|
{
|
|
int i;
|
|
std::string s;
|
|
|
|
cif::tie(i, s) = r.get("id", "s");
|
|
|
|
CHECK(i == n);
|
|
CHECK(s.compare(ts[n - 1]) == 0);
|
|
++n;
|
|
}
|
|
|
|
n = 1;
|
|
|
|
for (const auto &[i, s] : c.rows<int, std::string>("id", "s"))
|
|
{
|
|
CHECK(i == n);
|
|
CHECK(s.compare(ts[n - 1]) == 0);
|
|
++n;
|
|
}
|
|
}
|
|
|
|
TEST_CASE("c_2")
|
|
{
|
|
std::tuple<int, const char *> D[] = {
|
|
{ 1, "aap" },
|
|
{ 2, "noot" },
|
|
{ 3, "mies" }
|
|
};
|
|
|
|
cif::category c("foo");
|
|
|
|
for (const auto &[id, s] : D)
|
|
c.emplace({ { "id", id }, { "s", s } });
|
|
|
|
CHECK(not c.empty());
|
|
CHECK(c.size() == 3);
|
|
|
|
cif::category c2(c);
|
|
|
|
CHECK(not c2.empty());
|
|
CHECK(c2.size() == 3);
|
|
|
|
cif::category c3(std::move(c));
|
|
|
|
CHECK(not c3.empty());
|
|
CHECK(c3.size() == 3);
|
|
|
|
CHECK(c.empty()); // NOLINT(bugprone-use-after-move)
|
|
CHECK(c.size() == 0);
|
|
|
|
c = c3;
|
|
|
|
CHECK(not c.empty());
|
|
CHECK(c.size() == 3);
|
|
|
|
c = std::move(c2);
|
|
|
|
CHECK(not c.empty());
|
|
CHECK(c.size() == 3);
|
|
}
|
|
|
|
TEST_CASE("c_3")
|
|
{
|
|
std::tuple<int, const char *> D[] = {
|
|
{ 1, "aap" },
|
|
{ 2, "noot" },
|
|
{ 3, "mies" }
|
|
};
|
|
|
|
cif::category c("foo");
|
|
|
|
for (const auto &[id, s] : D)
|
|
c.emplace({ { "id", id }, { "s", s } });
|
|
|
|
cif::category c2("bar");
|
|
|
|
for (auto r : c)
|
|
c2.emplace(r);
|
|
|
|
// CHECK(c == c2);
|
|
}
|
|
|
|
TEST_CASE("ci_1")
|
|
{
|
|
cif::category c("foo");
|
|
|
|
c.emplace({ { "id", 1 }, { "s", "aap" } });
|
|
c.emplace({ { "id", 2 }, { "s", "noot" } });
|
|
c.emplace({ { "id", 3 }, { "s", "mies" } });
|
|
|
|
cif::category::iterator i1 = c.begin();
|
|
cif::category::const_iterator i2 = c.cbegin();
|
|
cif::category::const_iterator i3 = c.begin();
|
|
|
|
cif::category::const_iterator i4 = i2;
|
|
cif::category::const_iterator i5 = i1;
|
|
|
|
CHECK(i1 == i2);
|
|
CHECK(i1 == i3);
|
|
CHECK(i1 == i4);
|
|
CHECK(i1 == i5);
|
|
}
|
|
|
|
// TEST_CASE("os_1")
|
|
// {
|
|
// using namespace cif::literals;
|
|
// using namespace std::literals;
|
|
|
|
// std::tuple<int, const char *> D[] = {
|
|
// { 1, "aap" },
|
|
// { 2, "noot" },
|
|
// { 3, "mies" }
|
|
// };
|
|
|
|
// cif::category c("foo");
|
|
|
|
// for (const auto &[id, s] : D)
|
|
// c.emplace({ { "id", id }, { "s", s } });
|
|
|
|
// for (auto rh : c)
|
|
// {
|
|
// rh["o"].os(1, ',', 2, ": ", rh.get<std::string>("s"));
|
|
// }
|
|
|
|
// for (const auto &[id, s] : D)
|
|
// {
|
|
// auto rh = c.find1("id"_key == id);
|
|
|
|
// CHECK(rh.get<int>("id") == id);
|
|
// CHECK(rh.get<std::string>("s") == s);
|
|
// CHECK(rh.get<std::string>("o") == "1,2: "s + s);
|
|
// }
|
|
// }
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("get_1")
|
|
{
|
|
auto f = R"(data_TEST
|
|
#
|
|
loop_
|
|
_test.id
|
|
_test.name
|
|
1 aap
|
|
2 noot
|
|
3 mies
|
|
4 ?
|
|
5 .
|
|
)"_cf;
|
|
|
|
REQUIRE(f.size() == 1);
|
|
REQUIRE(f.contains("TEST"));
|
|
REQUIRE(f.front().size() == 1);
|
|
REQUIRE(f.front().contains("test"));
|
|
REQUIRE(f.front()["test"].size() == 5);
|
|
REQUIRE(f.front()["test"].front().size() == 2);
|
|
|
|
for (auto r : f.front()["test"])
|
|
{
|
|
int id;
|
|
std::optional<std::string> name;
|
|
|
|
cif::tie(id, name) = r.get("id", "name");
|
|
|
|
switch (id)
|
|
{
|
|
case 1:
|
|
REQUIRE(name.has_value());
|
|
CHECK(*name == "aap"); // NOLINT
|
|
break;
|
|
case 2:
|
|
REQUIRE(name.has_value());
|
|
CHECK(*name == "noot"); // NOLINT
|
|
break;
|
|
case 3:
|
|
REQUIRE(name.has_value());
|
|
CHECK(*name == "mies"); // NOLINT
|
|
break;
|
|
default: CHECK(name.has_value() == false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("f_1")
|
|
{
|
|
// using namespace mmcif;
|
|
|
|
auto f = R"(data_TEST
|
|
#
|
|
loop_
|
|
_test.id
|
|
_test.name
|
|
1 aap
|
|
2 noot
|
|
3 mies
|
|
)"_cf;
|
|
|
|
CHECK(f.empty() == false);
|
|
CHECK(f.size() == 1);
|
|
|
|
auto &db = f.front();
|
|
|
|
CHECK(db.name() == "TEST");
|
|
|
|
auto &test = db["test"];
|
|
CHECK(test.size() == 3);
|
|
|
|
const char *ts[] = { "aap", "noot", "mies" };
|
|
|
|
int n = 1;
|
|
for (const auto &[i, s] : test.rows<int, std::string>("id", "name"))
|
|
{
|
|
CHECK(i == n);
|
|
CHECK(s.compare(ts[n - 1]) == 0);
|
|
++n;
|
|
}
|
|
|
|
auto n2 = test.erase(cif::key("id") == 1, [](cif::row_handle r)
|
|
{
|
|
CHECK(r["id"].get<int>() == 1);
|
|
CHECK(r["name"].get<std::string>() == "aap"); });
|
|
|
|
CHECK(n2 == 1);
|
|
|
|
// for (auto r: test)
|
|
// test.erase(r);
|
|
|
|
test.clear();
|
|
CHECK(test.empty());
|
|
|
|
// fill again.
|
|
|
|
test.emplace({ { "id", "1" }, { "name", "aap" } });
|
|
test.emplace({ { "id", "2" }, { "name", "noot" } });
|
|
test.emplace({ { "id", "3" }, { "name", "mies" } });
|
|
|
|
n = 1;
|
|
for (const auto &[i, s] : test.rows<int, std::string>("id", "name"))
|
|
{
|
|
CHECK(i == n);
|
|
CHECK(s.compare(ts[n - 1]) == 0);
|
|
++n;
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("ut2")
|
|
{
|
|
// using namespace mmcif;
|
|
|
|
auto f = R"(data_TEST
|
|
#
|
|
loop_
|
|
_test.id
|
|
_test.name
|
|
_test.value
|
|
1 aap 1.0
|
|
2 noot 1.1
|
|
3 mies 1.2
|
|
)"_cf;
|
|
|
|
auto &db = f.front();
|
|
|
|
CHECK(db.name() == "TEST");
|
|
|
|
auto &test = db["test"];
|
|
CHECK(test.size() == 3);
|
|
|
|
int n = 0;
|
|
for (auto r : test.find(cif::key("name") == "aap"))
|
|
{
|
|
CHECK(++n == 1);
|
|
CHECK(r["id"].get<int>() == 1);
|
|
CHECK(r["name"].get<std::string>() == "aap");
|
|
CHECK(r["value"].get<float>() == 1.0f);
|
|
}
|
|
|
|
auto t = test.find(cif::key("id") == 1);
|
|
REQUIRE(not t.empty());
|
|
CHECK(t.front()["name"].get<std::string>() == "aap");
|
|
|
|
auto t2 = test.find(cif::key("value") == 1.2);
|
|
REQUIRE(not t2.empty());
|
|
CHECK(t2.front()["name"].get<std::string>() == "mies");
|
|
}
|
|
|
|
TEST_CASE("ut3")
|
|
{
|
|
using namespace cif::literals;
|
|
|
|
auto f = R"(data_TEST
|
|
#
|
|
loop_
|
|
_test.id
|
|
_test.name
|
|
_test.value
|
|
1 aap 1.0
|
|
2 noot 1.1
|
|
3 mies 1.2
|
|
4 boom .
|
|
5 roos ?
|
|
)"_cf;
|
|
|
|
auto &db = f.front();
|
|
|
|
CHECK(db.name() == "TEST");
|
|
|
|
auto &test = db["test"];
|
|
CHECK(test.size() == 5);
|
|
|
|
CHECK(test.contains("value"_key == cif::null));
|
|
CHECK(test.find("value"_key == cif::null).size() == 2);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("compare-with-float")
|
|
{
|
|
auto f = R"(data_TEST
|
|
#
|
|
loop_
|
|
_test.id
|
|
_test.value
|
|
1 1.0
|
|
2 2.0
|
|
3 3.0
|
|
4 ?
|
|
5 .
|
|
)"_cf;
|
|
|
|
auto &db = f.front();
|
|
auto &cat = db["test"];
|
|
|
|
CHECK(cat.find_first<int>(cif::key("value") == 1.0, "id") == 1);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("sw_1")
|
|
{
|
|
using namespace cif::literals;
|
|
|
|
auto f = R"(data_TEST
|
|
#
|
|
loop_
|
|
_test.id
|
|
_test.name
|
|
_test.value
|
|
1 aap 1.0
|
|
2 noot 1.1
|
|
3 mies 1.2
|
|
)"_cf;
|
|
|
|
auto &db = f.front();
|
|
auto &test = db["test"];
|
|
|
|
swap(test.front()["name"], test.back()["name"]);
|
|
|
|
CHECK(test.find1<std::string>("id"_key == 1, "name") == "mies");
|
|
CHECK(test.find1<std::string>("id"_key == 3, "name") == "aap");
|
|
|
|
swap(test.front()["name"], test.back()["name"]);
|
|
|
|
CHECK(test.find1<std::string>("id"_key == 1, "name") == "aap");
|
|
CHECK(test.find1<std::string>("id"_key == 3, "name") == "mies");
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("d0")
|
|
{
|
|
auto v = cif::validator_factory::instance().get("mmcif_pdbx.dic");
|
|
CHECK(v != nullptr);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("d1")
|
|
{
|
|
const char dict[] = R"(
|
|
data_test_dict.dic
|
|
_datablock.id test_dict.dic
|
|
_datablock.description
|
|
;
|
|
A test dictionary
|
|
;
|
|
_dictionary.title test_dict.dic
|
|
_dictionary.datablock_id test_dict.dic
|
|
_dictionary.version 1.0
|
|
|
|
loop_
|
|
_item_type_list.code
|
|
_item_type_list.primitive_code
|
|
_item_type_list.construct
|
|
_item_type_list.detail
|
|
code char
|
|
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
|
|
; code item types/single words ...
|
|
;
|
|
text char
|
|
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
|
|
; text item types / multi-line text ...
|
|
;
|
|
int numb
|
|
'[+-]?[0-9]+'
|
|
; int item types are the subset of numbers that are the negative
|
|
or positive integers.
|
|
;
|
|
|
|
save_cat_1
|
|
_category.description 'A simple test category'
|
|
_category.id cat_1
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_1.id'
|
|
|
|
save_
|
|
|
|
save__cat_1.id
|
|
_item.name '_cat_1.id'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_aliases.dictionary cif_core.dic
|
|
_item_aliases.version 2.0.1
|
|
_item_linked.child_name '_cat_2.parent_id'
|
|
_item_linked.parent_name '_cat_1.id'
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_1.name
|
|
_item.name '_cat_1.name'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_aliases.dictionary cif_core.dic
|
|
_item_aliases.version 2.0.1
|
|
_item_type.code text
|
|
save_
|
|
|
|
save_cat_2
|
|
_category.description 'A second simple test category'
|
|
_category.id cat_2
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_2.id'
|
|
save_
|
|
|
|
save__cat_2.id
|
|
_item.name '_cat_2.id'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_aliases.dictionary cif_core.dic
|
|
_item_aliases.version 2.0.1
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_2.parent_id
|
|
_item.name '_cat_2.parent_id'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_aliases.dictionary cif_core.dic
|
|
_item_aliases.version 2.0.1
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_2.desc
|
|
_item.name '_cat_2.desc'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_aliases.dictionary cif_core.dic
|
|
_item_aliases.version 2.0.1
|
|
_item_type.code text
|
|
save_
|
|
)";
|
|
|
|
struct membuf : public std::streambuf
|
|
{
|
|
membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
|
|
|
|
std::istream is_dict(&buffer);
|
|
|
|
cif::validator validator(is_dict);
|
|
|
|
cif::file f;
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
const char data[] = R"(
|
|
data_test
|
|
loop_
|
|
_cat_1.id
|
|
_cat_1.name
|
|
1 Aap
|
|
2 Noot
|
|
3 Mies
|
|
|
|
loop_
|
|
_cat_2.id
|
|
_cat_2.parent_id
|
|
_cat_2.desc
|
|
1 1 'Een dier'
|
|
2 1 'Een andere aap'
|
|
3 2 'walnoot bijvoorbeeld'
|
|
)";
|
|
|
|
struct data_membuf : public std::streambuf
|
|
{
|
|
data_membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
|
|
|
std::istream is_data(&data_buffer);
|
|
f.load(is_data);
|
|
f.front().set_validator(&validator);
|
|
|
|
SECTION("one")
|
|
{
|
|
auto &cat1 = f.front()["cat_1"];
|
|
auto &cat2 = f.front()["cat_2"];
|
|
|
|
CHECK(cat1.size() == 3);
|
|
CHECK(cat2.size() == 3);
|
|
|
|
cat1.erase(cif::key("id") == "1");
|
|
|
|
CHECK(cat1.size() == 2);
|
|
CHECK(cat2.size() == 1);
|
|
|
|
// CHECK_THROWS_AS(cat2.emplace({
|
|
// { "id", 4 },
|
|
// { "parent_id", 4 },
|
|
// { "desc", "moet fout gaan" }
|
|
// }), std::exception);
|
|
|
|
CHECK_THROWS_AS(cat2.emplace({ //
|
|
{ "id", "vijf" }, // <- invalid value
|
|
{ "parent_id", 2 },
|
|
{ "desc", "moet fout gaan" } }),
|
|
std::exception);
|
|
}
|
|
|
|
// SECTION("two")
|
|
// {
|
|
// auto &cat1 = f.front()["cat_1"];
|
|
// auto &cat2 = f.front()["cat_2"];
|
|
|
|
// cat1.update_value(cif::all(), "id", [](std::string_view v) -> std::string
|
|
// {
|
|
// int vi;
|
|
// auto [ec, ptr] = std::from_chars(v.data(), v.data() + v.length(), vi);
|
|
// return std::to_string(vi + 1);
|
|
// });
|
|
|
|
// CHECK(cat1.find1<std::string>(cif::key("id") == 2, "name") == "Aap");
|
|
// CHECK(cat1.find1<std::string>(cif::key("id") == 3, "name") == "Noot");
|
|
// CHECK(cat1.find1<std::string>(cif::key("id") == 4, "name") == "Mies");
|
|
|
|
// CHECK(cat2.find1<int>(cif::key("id") == 1, "parent_id") == 2);
|
|
// CHECK(cat2.find1<int>(cif::key("id") == 2, "parent_id") == 2);
|
|
// CHECK(cat2.find1<int>(cif::key("id") == 3, "parent_id") == 3);
|
|
// }
|
|
|
|
SECTION("three")
|
|
{
|
|
auto &cat2 = f.front()["cat_2"];
|
|
|
|
cat2.emplace({ { "id", "4" }, { "parent_id", "1" }, { "name", "Brulaap" } });
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("d2")
|
|
{
|
|
const char dict[] = R"(
|
|
data_test_dict.dic
|
|
_datablock.id test_dict.dic
|
|
_datablock.description
|
|
;
|
|
A test dictionary
|
|
;
|
|
_dictionary.title test_dict.dic
|
|
_dictionary.datablock_id test_dict.dic
|
|
_dictionary.version 1.0
|
|
|
|
loop_
|
|
_item_type_list.code
|
|
_item_type_list.primitive_code
|
|
_item_type_list.construct
|
|
_item_type_list.detail
|
|
code char
|
|
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
|
|
; code item types/single words ...
|
|
;
|
|
ucode uchar
|
|
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
|
|
; code item types/single words, case insensitive
|
|
;
|
|
text char
|
|
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
|
|
; text item types / multi-line text ...
|
|
;
|
|
int numb
|
|
'[+-]?[0-9]+'
|
|
; int item types are the subset of numbers that are the negative
|
|
or positive integers.
|
|
;
|
|
|
|
save_cat_1
|
|
_category.description 'A simple test category'
|
|
_category.id cat_1
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_1.id'
|
|
save_
|
|
|
|
save__cat_1.id
|
|
_item.name '_cat_1.id'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_1.c
|
|
_item.name '_cat_1.c'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_type.code ucode
|
|
save_
|
|
)";
|
|
|
|
struct membuf : public std::streambuf
|
|
{
|
|
membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
|
|
|
|
std::istream is_dict(&buffer);
|
|
|
|
cif::validator validator(is_dict);
|
|
|
|
cif::file f;
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
const char data[] = R"(
|
|
data_test
|
|
loop_
|
|
_cat_1.id
|
|
_cat_1.c
|
|
aap Aap
|
|
noot Noot
|
|
mies Mies
|
|
)";
|
|
|
|
struct data_membuf : public std::streambuf
|
|
{
|
|
data_membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
|
|
|
std::istream is_data(&data_buffer);
|
|
f.load(is_data);
|
|
f.front().set_validator(&validator);
|
|
|
|
auto &cat1 = f.front()["cat_1"];
|
|
|
|
CHECK(cat1.size() == 3);
|
|
|
|
cat1.erase(cif::key("id") == "AAP");
|
|
|
|
CHECK(cat1.size() == 3);
|
|
|
|
cat1.erase(cif::key("id") == "noot");
|
|
|
|
CHECK(cat1.size() == 2);
|
|
|
|
// should fail with duplicate key:
|
|
CHECK_THROWS_AS(cat1.emplace({ //
|
|
{ "id", "aap" },
|
|
{ "c", "2e-aap" } }),
|
|
std::exception);
|
|
|
|
cat1.erase(cif::key("id") == "aap");
|
|
|
|
CHECK(cat1.size() == 1);
|
|
|
|
cat1.emplace({ //
|
|
{ "id", "aap" },
|
|
{ "c", "2e-aap" } });
|
|
|
|
CHECK(cat1.size() == 2);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("d3")
|
|
{
|
|
const char dict[] = R"(
|
|
data_test_dict.dic
|
|
_datablock.id test_dict.dic
|
|
_datablock.description
|
|
;
|
|
A test dictionary
|
|
;
|
|
_dictionary.title test_dict.dic
|
|
_dictionary.datablock_id test_dict.dic
|
|
_dictionary.version 1.0
|
|
|
|
loop_
|
|
_item_type_list.code
|
|
_item_type_list.primitive_code
|
|
_item_type_list.construct
|
|
code char
|
|
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
|
|
|
|
text char
|
|
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
|
|
|
|
int numb
|
|
'[+-]?[0-9]+'
|
|
|
|
save_cat_1
|
|
_category.description 'A simple test category'
|
|
_category.id cat_1
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_1.id'
|
|
|
|
save_
|
|
|
|
save__cat_1.id
|
|
_item.name '_cat_1.id'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_linked.child_name '_cat_2.parent_id'
|
|
_item_linked.parent_name '_cat_1.id'
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_1.name1
|
|
_item.name '_cat_1.name1'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_type.code text
|
|
save_
|
|
|
|
save__cat_1.name2
|
|
_item.name '_cat_1.name2'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code no
|
|
_item_linked.child_name '_cat_2.name2'
|
|
_item_linked.parent_name '_cat_1.name2'
|
|
_item_type.code text
|
|
save_
|
|
|
|
save_cat_2
|
|
_category.description 'A second simple test category'
|
|
_category.id cat_2
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_2.id'
|
|
save_
|
|
|
|
save__cat_2.id
|
|
_item.name '_cat_2.id'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_2.parent_id
|
|
_item.name '_cat_2.parent_id'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_2.name2
|
|
_item.name '_cat_2.name2'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code no
|
|
_item_type.code text
|
|
save_
|
|
|
|
save__cat_2.desc
|
|
_item.name '_cat_2.desc'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code text
|
|
save_
|
|
)";
|
|
|
|
struct membuf : public std::streambuf
|
|
{
|
|
membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
|
|
|
|
std::istream is_dict(&buffer);
|
|
|
|
cif::validator validator(is_dict);
|
|
|
|
cif::file f;
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
const char data[] = R"(
|
|
data_test
|
|
loop_
|
|
_cat_1.id
|
|
_cat_1.name1
|
|
_cat_1.name2
|
|
1 Aap aap
|
|
2 Noot noot
|
|
3 Mies mies
|
|
|
|
loop_
|
|
_cat_2.id
|
|
_cat_2.parent_id
|
|
_cat_2.name2
|
|
_cat_2.desc
|
|
1 1 aap 'Een dier'
|
|
2 1 . 'Een andere aap'
|
|
3 2 noot 'walnoot bijvoorbeeld'
|
|
4 2 n2 hazelnoot
|
|
)";
|
|
|
|
struct data_membuf : public std::streambuf
|
|
{
|
|
data_membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
|
|
|
std::istream is_data(&data_buffer);
|
|
f.load(is_data);
|
|
f.front().set_validator(&validator);
|
|
|
|
auto &cat1 = f.front()["cat_1"];
|
|
auto &cat2 = f.front()["cat_2"];
|
|
|
|
// check a rename in parent and child
|
|
|
|
for (auto r : cat1.find(cif::key("id") == "1"))
|
|
{
|
|
r["id"] = "10";
|
|
break;
|
|
}
|
|
|
|
CHECK(cat1.size() == 3);
|
|
CHECK(cat2.size() == 4);
|
|
|
|
CHECK(cat1.find(cif::key("id") == "1").size() == 0);
|
|
CHECK(cat1.find(cif::key("id") == "10").size() == 1);
|
|
|
|
CHECK(cat2.find(cif::key("parent_id") == "1").size() == 0);
|
|
CHECK(cat2.find(cif::key("parent_id") == "10").size() == 2);
|
|
|
|
// check a rename in parent and child, this time only one child should be renamed
|
|
|
|
for (auto r : cat1.find(cif::key("id") == "2"))
|
|
{
|
|
r["id"] = "20";
|
|
break;
|
|
}
|
|
|
|
CHECK(cat1.size() == 3);
|
|
CHECK(cat2.size() == 4);
|
|
|
|
CHECK(cat1.find(cif::key("id") == "2").size() == 0);
|
|
CHECK(cat1.find(cif::key("id") == "20").size() == 1);
|
|
|
|
CHECK(cat2.find(cif::key("parent_id") == "2").size() == 1);
|
|
CHECK(cat2.find(cif::key("parent_id") == "20").size() == 1);
|
|
|
|
CHECK(cat2.find(cif::key("parent_id") == "2" and cif::key("name2") == "noot").size() == 0);
|
|
CHECK(cat2.find(cif::key("parent_id") == "2" and cif::key("name2") == "n2").size() == 1);
|
|
CHECK(cat2.find(cif::key("parent_id") == "20" and cif::key("name2") == "noot").size() == 1);
|
|
CHECK(cat2.find(cif::key("parent_id") == "20" and cif::key("name2") == "n2").size() == 0);
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
cat1.erase(cif::key("id") == "10");
|
|
|
|
CHECK(cat1.size() == 2);
|
|
CHECK(cat2.size() == 2); // TODO: Is this really what we want?
|
|
|
|
cat1.erase(cif::key("id") == "20");
|
|
|
|
CHECK(cat1.size() == 1);
|
|
CHECK(cat2.size() == 1); // TODO: Is this really what we want?
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("d4")
|
|
{
|
|
const char dict[] = R"(
|
|
data_test_dict.dic
|
|
_datablock.id test_dict.dic
|
|
_datablock.description
|
|
;
|
|
A test dictionary
|
|
;
|
|
_dictionary.title test_dict.dic
|
|
_dictionary.datablock_id test_dict.dic
|
|
_dictionary.version 1.0
|
|
|
|
loop_
|
|
_item_type_list.code
|
|
_item_type_list.primitive_code
|
|
_item_type_list.construct
|
|
code char
|
|
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
|
|
|
|
text char
|
|
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
|
|
|
|
int numb
|
|
'[+-]?[0-9]+'
|
|
|
|
save_cat_1
|
|
_category.description 'A simple test category'
|
|
_category.id cat_1
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_1.id'
|
|
save_
|
|
|
|
save__cat_1.id
|
|
_item.name '_cat_1.id'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_linked.child_name '_cat_2.parent_id'
|
|
_item_linked.parent_name '_cat_1.id'
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_1.id2
|
|
_item.name '_cat_1.id2'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code no
|
|
_item_linked.child_name '_cat_2.parent_id2'
|
|
_item_linked.parent_name '_cat_1.id2'
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_1.id3
|
|
_item.name '_cat_1.id3'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code no
|
|
_item_linked.child_name '_cat_2.parent_id3'
|
|
_item_linked.parent_name '_cat_1.id3'
|
|
_item_type.code text
|
|
save_
|
|
|
|
save_cat_2
|
|
_category.description 'A second simple test category'
|
|
_category.id cat_2
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_2.id'
|
|
save_
|
|
|
|
save__cat_2.id
|
|
_item.name '_cat_2.id'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_2.parent_id
|
|
_item.name '_cat_2.parent_id'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
save_
|
|
|
|
save__cat_2.parent_id2
|
|
_item.name '_cat_2.parent_id2'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code no
|
|
save_
|
|
|
|
save__cat_2.parent_id3
|
|
_item.name '_cat_2.parent_id3'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code no
|
|
save_
|
|
|
|
)";
|
|
|
|
struct membuf : public std::streambuf
|
|
{
|
|
membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
|
|
|
|
std::istream is_dict(&buffer);
|
|
|
|
cif::validator validator(is_dict);
|
|
|
|
cif::file f;
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
const char data[] = R"(
|
|
data_test
|
|
loop_
|
|
_cat_1.id
|
|
_cat_1.id2
|
|
_cat_1.id3
|
|
1 aap aap
|
|
2 . noot
|
|
3 mies .
|
|
4 . .
|
|
|
|
loop_
|
|
_cat_2.id
|
|
_cat_2.parent_id
|
|
_cat_2.parent_id2
|
|
_cat_2.parent_id3
|
|
1 1 aap aap
|
|
2 1 . x
|
|
3 1 aap .
|
|
4 2 noot noot
|
|
5 2 . noot
|
|
6 2 noot .
|
|
7 2 . .
|
|
8 3 mies mies
|
|
9 3 . mies
|
|
10 3 mies .
|
|
11 4 roos roos
|
|
12 4 . roos
|
|
13 4 roos .
|
|
)";
|
|
|
|
struct data_membuf : public std::streambuf
|
|
{
|
|
data_membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
|
|
|
std::istream is_data(&data_buffer);
|
|
f.load(is_data);
|
|
f.front().set_validator(&validator);
|
|
|
|
auto &cat1 = f.front()["cat_1"];
|
|
auto &cat2 = f.front()["cat_2"];
|
|
|
|
// check a rename in parent and child
|
|
|
|
for (auto r : cat1.find(cif::key("id") == 1))
|
|
{
|
|
r["id"] = 10;
|
|
break;
|
|
}
|
|
|
|
CHECK(cat1.size() == 4);
|
|
CHECK(cat2.size() == 13);
|
|
|
|
CHECK(cat1.find(cif::key("id") == 1).size() == 0);
|
|
CHECK(cat1.find(cif::key("id") == 10).size() == 1);
|
|
|
|
CHECK(cat2.find(cif::key("parent_id") == 1).size() == 1);
|
|
CHECK(cat2.find(cif::key("parent_id") == 10).size() == 2);
|
|
|
|
for (auto r : cat1.find(cif::key("id") == 2))
|
|
{
|
|
r["id"] = 20;
|
|
break;
|
|
}
|
|
|
|
CHECK(cat1.size() == 4);
|
|
CHECK(cat2.size() == 13);
|
|
|
|
CHECK(cat1.find(cif::key("id") == 2).size() == 0);
|
|
CHECK(cat1.find(cif::key("id") == 20).size() == 1);
|
|
|
|
CHECK(cat2.find(cif::key("parent_id") == 2).size() == 2);
|
|
CHECK(cat2.find(cif::key("parent_id") == 20).size() == 2);
|
|
|
|
for (auto r : cat1.find(cif::key("id") == 3))
|
|
{
|
|
r["id"] = 30;
|
|
break;
|
|
}
|
|
|
|
CHECK(cat1.size() == 4);
|
|
CHECK(cat2.size() == 13);
|
|
|
|
CHECK(cat1.find(cif::key("id") == 3).size() == 0);
|
|
CHECK(cat1.find(cif::key("id") == 30).size() == 1);
|
|
|
|
CHECK(cat2.find(cif::key("parent_id") == 3).size() == 2);
|
|
CHECK(cat2.find(cif::key("parent_id") == 30).size() == 1);
|
|
|
|
for (auto r : cat1.find(cif::key("id") == 4))
|
|
{
|
|
r["id"] = 40;
|
|
break;
|
|
}
|
|
|
|
CHECK(cat1.size() == 4);
|
|
CHECK(cat2.size() == 13);
|
|
|
|
CHECK(cat1.find(cif::key("id") == 4).size() == 0);
|
|
CHECK(cat1.find(cif::key("id") == 10).size() == 1);
|
|
|
|
CHECK(cat2.find(cif::key("parent_id") == 4).size() == 3);
|
|
CHECK(cat2.find(cif::key("parent_id") == 40).size() == 0);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("d5")
|
|
{
|
|
const char dict[] = R"(
|
|
data_test_dict.dic
|
|
_datablock.id test_dict.dic
|
|
_datablock.description
|
|
;
|
|
A test dictionary
|
|
;
|
|
_dictionary.title test_dict.dic
|
|
_dictionary.datablock_id test_dict.dic
|
|
_dictionary.version 1.0
|
|
|
|
loop_
|
|
_item_type_list.code
|
|
_item_type_list.primitive_code
|
|
_item_type_list.construct
|
|
code char
|
|
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
|
|
|
|
text char
|
|
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
|
|
|
|
int numb
|
|
'[+-]?[0-9]+'
|
|
|
|
save_cat_1
|
|
_category.description 'A simple test category'
|
|
_category.id cat_1
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_1.id'
|
|
save_
|
|
|
|
save__cat_1.id
|
|
_item.name '_cat_1.id'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
save_cat_2
|
|
_category.description 'A second simple test category'
|
|
_category.id cat_2
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_2.id'
|
|
save_
|
|
|
|
save__cat_2.id
|
|
_item.name '_cat_2.id'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_2.parent_id
|
|
_item.name '_cat_2.parent_id'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
save_
|
|
|
|
save__cat_2.parent_id2
|
|
_item.name '_cat_2.parent_id2'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code no
|
|
save_
|
|
|
|
save__cat_2.parent_id3
|
|
_item.name '_cat_2.parent_id3'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code no
|
|
save_
|
|
|
|
loop_
|
|
_pdbx_item_linked_group_list.child_category_id
|
|
_pdbx_item_linked_group_list.link_group_id
|
|
_pdbx_item_linked_group_list.child_name
|
|
_pdbx_item_linked_group_list.parent_name
|
|
_pdbx_item_linked_group_list.parent_category_id
|
|
cat_2 1 '_cat_2.parent_id' '_cat_1.id' cat_1
|
|
cat_2 2 '_cat_2.parent_id2' '_cat_1.id' cat_1
|
|
cat_2 3 '_cat_2.parent_id3' '_cat_1.id' cat_1
|
|
|
|
loop_
|
|
_pdbx_item_linked_group.category_id
|
|
_pdbx_item_linked_group.link_group_id
|
|
_pdbx_item_linked_group.label
|
|
cat_2 1 cat_2:cat_1:1
|
|
cat_2 2 cat_2:cat_1:2
|
|
cat_2 3 cat_2:cat_1:3
|
|
)";
|
|
|
|
struct membuf : public std::streambuf
|
|
{
|
|
membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
|
|
|
|
std::istream is_dict(&buffer);
|
|
|
|
cif::validator validator(is_dict);
|
|
|
|
cif::file f;
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
const char data[] = R"(
|
|
data_test
|
|
loop_
|
|
_cat_1.id
|
|
1
|
|
2
|
|
3
|
|
|
|
loop_
|
|
_cat_2.id
|
|
_cat_2.parent_id
|
|
_cat_2.parent_id2
|
|
_cat_2.parent_id3
|
|
1 1 ? ?
|
|
2 ? 1 ?
|
|
3 ? ? 1
|
|
4 2 2 ?
|
|
5 2 ? 2
|
|
6 ? 2 2
|
|
7 3 3 3
|
|
)";
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
struct data_membuf : public std::streambuf
|
|
{
|
|
data_membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
|
|
|
std::istream is_data(&data_buffer);
|
|
f.load(is_data);
|
|
f.front().set_validator(&validator);
|
|
|
|
auto &cat1 = f.front()["cat_1"];
|
|
auto &cat2 = f.front()["cat_2"];
|
|
|
|
// --------------------------------------------------------------------
|
|
// check iterate children
|
|
|
|
auto PR2set = cat1.find(cif::key("id") == 2);
|
|
REQUIRE(PR2set.size() == 1);
|
|
auto PR2 = PR2set.front();
|
|
CHECK(PR2["id"].get<int>() == 2);
|
|
|
|
auto CR2set = cat1.get_children(PR2, cat2);
|
|
CHECK(CR2set.size() == 3);
|
|
|
|
std::vector<int> CRids;
|
|
std::ranges::transform(CR2set, std::back_inserter(CRids), [](cif::row_handle r)
|
|
{ return r["id"].get<int>(); });
|
|
std::ranges::sort(CRids);
|
|
CHECK(CRids == std::vector<int>({ 4, 5, 6 }));
|
|
|
|
// check a rename in parent and child
|
|
|
|
for (auto r : cat1.find(cif::key("id") == 1))
|
|
{
|
|
r["id"] = 10;
|
|
break;
|
|
}
|
|
|
|
CHECK(cat1.size() == 3);
|
|
CHECK(cat2.size() == 7);
|
|
|
|
CHECK(cat1.find(cif::key("id") == 1).size() == 0);
|
|
CHECK(cat1.find(cif::key("id") == 10).size() == 1);
|
|
|
|
CHECK(cat2.find(cif::key("parent_id") == 1).size() == 0);
|
|
CHECK(cat2.find(cif::key("parent_id2") == 1).size() == 0);
|
|
CHECK(cat2.find(cif::key("parent_id3") == 1).size() == 0);
|
|
CHECK(cat2.find(cif::key("parent_id") == 10).size() == 1);
|
|
CHECK(cat2.find(cif::key("parent_id2") == 10).size() == 1);
|
|
CHECK(cat2.find(cif::key("parent_id3") == 10).size() == 1);
|
|
|
|
for (auto r : cat1.find(cif::key("id") == 2))
|
|
{
|
|
r["id"] = 20;
|
|
break;
|
|
}
|
|
|
|
CHECK(cat1.size() == 3);
|
|
CHECK(cat2.size() == 7);
|
|
|
|
CHECK(cat1.find(cif::key("id") == 2).size() == 0);
|
|
CHECK(cat1.find(cif::key("id") == 20).size() == 1);
|
|
|
|
CHECK(cat2.find(cif::key("parent_id") == 2).size() == 0);
|
|
CHECK(cat2.find(cif::key("parent_id2") == 2).size() == 0);
|
|
CHECK(cat2.find(cif::key("parent_id3") == 2).size() == 0);
|
|
CHECK(cat2.find(cif::key("parent_id") == 20).size() == 2);
|
|
CHECK(cat2.find(cif::key("parent_id2") == 20).size() == 2);
|
|
CHECK(cat2.find(cif::key("parent_id3") == 20).size() == 2);
|
|
|
|
for (auto r : cat1.find(cif::key("id") == 3))
|
|
{
|
|
r["id"] = 30;
|
|
break;
|
|
}
|
|
|
|
CHECK(cat1.size() == 3);
|
|
CHECK(cat2.size() == 7);
|
|
|
|
CHECK(cat1.find(cif::key("id") == 3).size() == 0);
|
|
CHECK(cat1.find(cif::key("id") == 30).size() == 1);
|
|
|
|
CHECK(cat2.find(cif::key("parent_id") == 3).size() == 0);
|
|
CHECK(cat2.find(cif::key("parent_id2") == 3).size() == 0);
|
|
CHECK(cat2.find(cif::key("parent_id3") == 3).size() == 0);
|
|
CHECK(cat2.find(cif::key("parent_id") == 30).size() == 1);
|
|
CHECK(cat2.find(cif::key("parent_id2") == 30).size() == 1);
|
|
CHECK(cat2.find(cif::key("parent_id3") == 30).size() == 1);
|
|
|
|
// test delete
|
|
|
|
cat1.erase(cif::key("id") == 10);
|
|
CHECK(cat1.size() == 2);
|
|
CHECK(cat2.size() == 4);
|
|
|
|
cat1.erase(cif::key("id") == 20);
|
|
CHECK(cat1.size() == 1);
|
|
CHECK(cat2.size() == 1);
|
|
|
|
cat1.erase(cif::key("id") == 30);
|
|
CHECK(cat1.size() == 0);
|
|
CHECK(cat2.size() == 0);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("d6")
|
|
{
|
|
const char dict[] = R"(
|
|
data_test_dict.dic
|
|
_datablock.id test_dict.dic
|
|
_datablock.description
|
|
;
|
|
A test dictionary
|
|
;
|
|
_dictionary.title test_dict.dic
|
|
_dictionary.datablock_id test_dict.dic
|
|
_dictionary.version 1.0
|
|
|
|
loop_
|
|
_item_type_list.code
|
|
_item_type_list.primitive_code
|
|
_item_type_list.construct
|
|
code char
|
|
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
|
|
|
|
text char
|
|
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
|
|
|
|
int numb
|
|
'[+-]?[0-9]+'
|
|
|
|
save_cat_1
|
|
_category.description 'A simple test category'
|
|
_category.id cat_1
|
|
_category.mandatory_code yes
|
|
_category_key.name '_cat_1.id'
|
|
save_
|
|
|
|
save__cat_1.id
|
|
_item.name '_cat_1.id'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_1.id_2
|
|
_item.name '_cat_1.id_2'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code no
|
|
_item_type.code int
|
|
save_
|
|
|
|
save_cat_2
|
|
_category.description 'A second simple test category'
|
|
_category.id cat_2
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_2.id'
|
|
save_
|
|
|
|
save__cat_2.id
|
|
_item.name '_cat_2.id'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_2.parent_id
|
|
_item.name '_cat_2.parent_id'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
save_
|
|
|
|
save__cat_2.parent_id_2
|
|
_item.name '_cat_2.parent_id_2'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code no
|
|
save_
|
|
|
|
loop_
|
|
_pdbx_item_linked_group_list.child_category_id
|
|
_pdbx_item_linked_group_list.link_group_id
|
|
_pdbx_item_linked_group_list.child_name
|
|
_pdbx_item_linked_group_list.parent_name
|
|
_pdbx_item_linked_group_list.parent_category_id
|
|
cat_2 1 '_cat_2.parent_id' '_cat_1.id' cat_1
|
|
cat_2 1 '_cat_2.parent_id_2' '_cat_1.id_2' cat_1
|
|
|
|
loop_
|
|
_pdbx_item_linked_group.category_id
|
|
_pdbx_item_linked_group.link_group_id
|
|
_pdbx_item_linked_group.label
|
|
cat_2 1 cat_2:cat_1:1
|
|
)";
|
|
|
|
struct membuf : public std::streambuf
|
|
{
|
|
membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
|
|
|
|
std::istream is_dict(&buffer);
|
|
|
|
cif::validator validator(is_dict);
|
|
|
|
cif::file f;
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
const char data[] = R"(
|
|
data_test
|
|
loop_
|
|
_cat_1.id
|
|
_cat_1.id_2
|
|
1 1
|
|
2 2
|
|
3 ?
|
|
|
|
loop_
|
|
_cat_2.id
|
|
_cat_2.parent_id
|
|
_cat_2.parent_id_2
|
|
0 1 1
|
|
1 1 ?
|
|
2 ? 1
|
|
3 ? ?
|
|
4 2 2
|
|
5 3 1
|
|
6 3 ?
|
|
)";
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
struct data_membuf : public std::streambuf
|
|
{
|
|
data_membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
|
|
|
std::istream is_data(&data_buffer);
|
|
f.load(is_data);
|
|
f.front().set_validator(&validator);
|
|
|
|
// auto &cat1 = f.front()["cat_1"];
|
|
auto &cat2 = f.front()["cat_2"];
|
|
|
|
// f.front().validate_links();
|
|
// CHECK(not );
|
|
|
|
using namespace cif::literals;
|
|
|
|
CHECK(cat2.has_parents(cat2.find1("id"_key == 0)));
|
|
CHECK(cat2.has_parents(cat2.find1("id"_key == 1)));
|
|
CHECK(cat2.has_parents(cat2.find1("id"_key == 2)));
|
|
CHECK(not cat2.has_parents(cat2.find1("id"_key == 3)));
|
|
CHECK(cat2.has_parents(cat2.find1("id"_key == 4)));
|
|
CHECK(not cat2.has_parents(cat2.find1("id"_key == 5)));
|
|
CHECK(cat2.has_parents(cat2.find1("id"_key == 6)));
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("c1")
|
|
{
|
|
cif::VERBOSE = 1;
|
|
|
|
auto f = R"(data_TEST
|
|
#
|
|
loop_
|
|
_test.id
|
|
_test.name
|
|
1 aap
|
|
2 noot
|
|
3 mies
|
|
4 .
|
|
5 ?
|
|
)"_cf;
|
|
|
|
auto &db = f.front();
|
|
|
|
for (auto r : db["test"].find(cif::key("id") == 1))
|
|
{
|
|
const auto &[id, name] = r.get<int, std::string>("id", "name");
|
|
CHECK(id == 1);
|
|
CHECK(name == "aap");
|
|
}
|
|
|
|
for (auto r : db["test"].find(cif::key("id") == 4))
|
|
{
|
|
const auto &[id, name] = r.get<int, std::string>("id", "name");
|
|
CHECK(id == 4);
|
|
CHECK(name.empty());
|
|
}
|
|
|
|
for (auto r : db["test"].find(cif::key("id") == 5))
|
|
{
|
|
const auto &[id, name] = r.get<int, std::string>("id", "name");
|
|
CHECK(id == 5);
|
|
CHECK(name.empty());
|
|
}
|
|
|
|
// optional
|
|
|
|
for (auto r : db["test"])
|
|
{
|
|
const auto &[id, name] = r.get<int, std::optional<std::string>>("id", "name");
|
|
switch (id)
|
|
{
|
|
case 1: CHECK(name == "aap"); break;
|
|
case 2: CHECK(name == "noot"); break;
|
|
case 3: CHECK(name == "mies"); break;
|
|
case 4:
|
|
case 5: CHECK(not name); break;
|
|
default:
|
|
CHECK(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("c2")
|
|
{
|
|
cif::VERBOSE = 1;
|
|
|
|
auto f = R"(data_TEST
|
|
#
|
|
loop_
|
|
_test.id
|
|
_test.name
|
|
1 aap
|
|
2 noot
|
|
3 mies
|
|
4 .
|
|
5 ?
|
|
)"_cf;
|
|
|
|
auto &db = f.front();
|
|
|
|
// query tests
|
|
|
|
for (const auto &[id, name] : db["test"].rows<int, std::optional<std::string>>("id", "name"))
|
|
{
|
|
switch (id)
|
|
{
|
|
case 1: CHECK(name == "aap"); break;
|
|
case 2: CHECK(name == "noot"); break;
|
|
case 3: CHECK(name == "mies"); break;
|
|
case 4:
|
|
case 5: CHECK(not name); break;
|
|
default:
|
|
CHECK(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("c3")
|
|
{
|
|
auto f = R"(data_TEST
|
|
#
|
|
loop_
|
|
_test.id
|
|
_test.name
|
|
1 aap
|
|
2 noot
|
|
3 mies
|
|
4 .
|
|
5 ?
|
|
)"_cf;
|
|
|
|
auto &db = f.front();
|
|
|
|
// query tests
|
|
for (const auto &[id, name] : db["test"].find<int, std::optional<std::string>>(cif::all(), "id", "name"))
|
|
{
|
|
switch (id)
|
|
{
|
|
case 1: CHECK(name == "aap"); break;
|
|
case 2: CHECK(name == "noot"); break;
|
|
case 3: CHECK(name == "mies"); break;
|
|
case 4:
|
|
case 5: CHECK(not name); break;
|
|
default:
|
|
CHECK(false);
|
|
}
|
|
}
|
|
|
|
const auto &[id, name] = db["test"].find1<int, std::string>(cif::key("id") == 1, "id", "name");
|
|
|
|
CHECK(id == 1);
|
|
CHECK(name == "aap");
|
|
}
|
|
|
|
TEST_CASE("c4")
|
|
{
|
|
auto f = R"(data_TEST
|
|
#
|
|
loop_
|
|
_test.id
|
|
_test.name
|
|
1 aap
|
|
2 noot
|
|
3 mies
|
|
4 .
|
|
5 ?
|
|
)"_cf;
|
|
|
|
auto &db = f.front();
|
|
|
|
// query tests
|
|
CHECK(db["test"].find_max<int>("id") == 5);
|
|
CHECK(db["test"].find_max<int>("id", cif::key("name") != cif::null) == 3);
|
|
|
|
CHECK(db["test"].find_min<int>("id") == 1);
|
|
CHECK(db["test"].find_min<int>("id", cif::key("name") == cif::null) == 4);
|
|
|
|
// count tests
|
|
CHECK(db["test"].count(cif::all()) == 5);
|
|
CHECK(db["test"].count(cif::key("name") != cif::null) == 3);
|
|
CHECK(db["test"].count(cif::key("name") == cif::null) == 2);
|
|
|
|
// find_first tests
|
|
CHECK(db["test"].find_first<int>(cif::key("id") == 1, "id") == 1);
|
|
CHECK(db["test"].find_first<int>(cif::all(), "id") == 1);
|
|
|
|
std::optional<int> v;
|
|
|
|
v = db["test"].find_first<std::optional<int>>(cif::key("id") == 1, "id");
|
|
REQUIRE(v.has_value());
|
|
CHECK(*v == 1); // NOLINT
|
|
|
|
v = db["test"].find_first<std::optional<int>>(cif::key("id") == 6, "id");
|
|
CHECK(not v.has_value());
|
|
|
|
// find1 tests
|
|
CHECK(db["test"].find1<int>(cif::key("id") == 1, "id") == 1);
|
|
CHECK_THROWS_AS(db["test"].find1<int>(cif::all(), "id"), cif::multiple_results_error);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// rename test
|
|
|
|
TEST_CASE("r1")
|
|
{
|
|
/*
|
|
Rationale:
|
|
|
|
The mmcif_pdbx.dic dictionary contains inconsistent child-parent relations. E.g. atom_site is parent
|
|
of pdbx_nonpoly_scheme which itself is a parent of pdbx_entity_nonpoly. If I want to rename a residue
|
|
I cannot update pdbx_nonpoly_scheme since changing a parent changes children, but not vice versa.
|
|
|
|
But if I change the comp_id in atom_site, the pdbx_nonpoly_scheme is updated, that's good, and then
|
|
pdbx_entity_nonpoly is updated and that's bad.
|
|
|
|
The idea is now that if we update a parent and a child that must change as well, we first check
|
|
if there are more parents of this child that will not change. In that case we have to split the
|
|
child into two, one with the new value and one with the old. We then of course have to split all
|
|
children of this split row that are direct children.
|
|
*/
|
|
|
|
const char dict[] = R"(
|
|
data_test_dict.dic
|
|
_datablock.id test_dict.dic
|
|
_datablock.description
|
|
;
|
|
A test dictionary
|
|
;
|
|
_dictionary.title test_dict.dic
|
|
_dictionary.datablock_id test_dict.dic
|
|
_dictionary.version 1.0
|
|
|
|
loop_
|
|
_item_type_list.code
|
|
_item_type_list.primitive_code
|
|
_item_type_list.construct
|
|
code char
|
|
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
|
|
|
|
text char
|
|
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
|
|
|
|
int numb
|
|
'[+-]?[0-9]+'
|
|
|
|
save_cat_1
|
|
_category.description 'A simple test category'
|
|
_category.id cat_1
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_1.id'
|
|
save_
|
|
|
|
save__cat_1.id
|
|
_item.name '_cat_1.id'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_linked.child_name '_cat_2.parent_id'
|
|
_item_linked.parent_name '_cat_1.id'
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_1.name
|
|
_item.name '_cat_1.name'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_1.desc
|
|
_item.name '_cat_1.desc'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_type.code text
|
|
save_
|
|
|
|
save_cat_2
|
|
_category.description 'A second simple test category'
|
|
_category.id cat_2
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_2.id'
|
|
save_
|
|
|
|
save__cat_2.id
|
|
_item.name '_cat_2.id'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_2.name
|
|
_item.name '_cat_2.name'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_2.num
|
|
_item.name '_cat_2.num'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_2.desc
|
|
_item.name '_cat_2.desc'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code text
|
|
save_
|
|
|
|
save_cat_3
|
|
_category.description 'A third simple test category'
|
|
_category.id cat_3
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_3.id'
|
|
save_
|
|
|
|
save__cat_3.id
|
|
_item.name '_cat_3.id'
|
|
_item.category_id cat_3
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_3.name
|
|
_item.name '_cat_3.name'
|
|
_item.category_id cat_3
|
|
_item.mandatory_code yes
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_3.num
|
|
_item.name '_cat_3.num'
|
|
_item.category_id cat_3
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
loop_
|
|
_pdbx_item_linked_group_list.child_category_id
|
|
_pdbx_item_linked_group_list.link_group_id
|
|
_pdbx_item_linked_group_list.child_name
|
|
_pdbx_item_linked_group_list.parent_name
|
|
_pdbx_item_linked_group_list.parent_category_id
|
|
cat_1 1 '_cat_1.name' '_cat_2.name' cat_2
|
|
cat_2 1 '_cat_2.name' '_cat_3.name' cat_3
|
|
cat_2 1 '_cat_2.num' '_cat_3.num' cat_3
|
|
|
|
)";
|
|
|
|
struct membuf : public std::streambuf
|
|
{
|
|
membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
|
|
|
|
std::istream is_dict(&buffer);
|
|
|
|
cif::validator validator(is_dict);
|
|
|
|
cif::file f;
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
const char data[] = R"(
|
|
data_test
|
|
loop_
|
|
_cat_1.id
|
|
_cat_1.name
|
|
_cat_1.desc
|
|
1 aap Aap
|
|
2 noot Noot
|
|
3 mies Mies
|
|
|
|
loop_
|
|
_cat_2.id
|
|
_cat_2.name
|
|
_cat_2.num
|
|
_cat_2.desc
|
|
1 aap 1 'Een dier'
|
|
2 aap 2 'Een andere aap'
|
|
3 noot 1 'walnoot bijvoorbeeld'
|
|
|
|
loop_
|
|
_cat_3.id
|
|
_cat_3.name
|
|
_cat_3.num
|
|
1 aap 1
|
|
2 aap 2
|
|
)";
|
|
|
|
using namespace cif::literals;
|
|
|
|
struct data_membuf : public std::streambuf
|
|
{
|
|
data_membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
|
|
|
std::istream is_data(&data_buffer);
|
|
f.load(is_data);
|
|
f.front().set_validator(&validator);
|
|
|
|
auto &cat1 = f.front()["cat_1"];
|
|
auto &cat2 = f.front()["cat_2"];
|
|
auto &cat3 = f.front()["cat_3"];
|
|
|
|
cat3.update_value("name"_key == "aap" and "num"_key == 1, "name", "aapje");
|
|
|
|
CHECK(cat3.size() == 2);
|
|
|
|
{
|
|
int id, num;
|
|
std::string name;
|
|
cif::tie(id, name, num) = cat3.front().get("id", "name", "num");
|
|
CHECK(id == 1);
|
|
CHECK(num == 1);
|
|
CHECK(name == "aapje");
|
|
|
|
cif::tie(id, name, num) = cat3.back().get("id", "name", "num");
|
|
CHECK(id == 2);
|
|
CHECK(num == 2);
|
|
CHECK(name == "aap");
|
|
}
|
|
|
|
int i = 0;
|
|
for (const auto &[id, name, num, desc] : cat2.rows<int, std::string, int, std::string>("id", "name", "num", "desc"))
|
|
{
|
|
switch (++i)
|
|
{
|
|
case 1:
|
|
CHECK(id == 1);
|
|
CHECK(num == 1);
|
|
CHECK(name == "aapje");
|
|
CHECK(desc == "Een dier");
|
|
break;
|
|
|
|
case 2:
|
|
CHECK(id == 2);
|
|
CHECK(num == 2);
|
|
CHECK(name == "aap");
|
|
CHECK(desc == "Een andere aap");
|
|
break;
|
|
|
|
case 3:
|
|
CHECK(id == 3);
|
|
CHECK(num == 1);
|
|
CHECK(name == "noot");
|
|
CHECK(desc == "walnoot bijvoorbeeld");
|
|
break;
|
|
|
|
default:
|
|
CHECK(false /*"Unexpected record"*/);
|
|
}
|
|
}
|
|
|
|
CHECK(cat1.size() == 4);
|
|
i = 0;
|
|
for (const auto &[id, name, desc] : cat1.rows<int, std::string, std::string>("id", "name", "desc"))
|
|
{
|
|
switch (++i)
|
|
{
|
|
case 1:
|
|
CHECK(id == 1);
|
|
CHECK(name == "aapje");
|
|
CHECK(desc == "Aap");
|
|
break;
|
|
|
|
case 2:
|
|
CHECK(id == 2);
|
|
CHECK(name == "noot");
|
|
CHECK(desc == "Noot");
|
|
break;
|
|
|
|
case 3:
|
|
CHECK(id == 3);
|
|
CHECK(name == "mies");
|
|
CHECK(desc == "Mies");
|
|
break;
|
|
|
|
case 4:
|
|
CHECK(id == 4);
|
|
CHECK(name == "aap");
|
|
CHECK(desc == "Aap");
|
|
break;
|
|
|
|
default:
|
|
CHECK(false /* "Unexpected record" */);
|
|
}
|
|
}
|
|
|
|
// f.save(std::cout);
|
|
}
|
|
|
|
TEST_CASE("pc_1")
|
|
{
|
|
/*
|
|
Parent/child tests
|
|
|
|
Note that the dictionary is different than the one in test r1
|
|
*/
|
|
|
|
const char dict[] = R"(
|
|
data_test_dict.dic
|
|
_datablock.id test_dict.dic
|
|
_datablock.description
|
|
;
|
|
A test dictionary
|
|
;
|
|
_dictionary.title test_dict.dic
|
|
_dictionary.datablock_id test_dict.dic
|
|
_dictionary.version 1.0
|
|
|
|
loop_
|
|
_item_type_list.code
|
|
_item_type_list.primitive_code
|
|
_item_type_list.construct
|
|
code char
|
|
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
|
|
|
|
text char
|
|
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
|
|
|
|
int numb
|
|
'[+-]?[0-9]+'
|
|
|
|
save_cat_1
|
|
_category.description 'A simple test category'
|
|
_category.id cat_1
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_1.id'
|
|
save_
|
|
|
|
save__cat_1.id
|
|
_item.name '_cat_1.id'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_linked.child_name '_cat_2.parent_id'
|
|
_item_linked.parent_name '_cat_1.id'
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_1.name
|
|
_item.name '_cat_1.name'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_1.desc
|
|
_item.name '_cat_1.desc'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_type.code text
|
|
save_
|
|
|
|
save_cat_2
|
|
_category.description 'A second simple test category'
|
|
_category.id cat_2
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_2.id'
|
|
save_
|
|
|
|
save__cat_2.id
|
|
_item.name '_cat_2.id'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_2.name
|
|
_item.name '_cat_2.name'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_2.num
|
|
_item.name '_cat_2.num'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_2.desc
|
|
_item.name '_cat_2.desc'
|
|
_item.category_id cat_2
|
|
_item.mandatory_code yes
|
|
_item_type.code text
|
|
save_
|
|
|
|
save_cat_3
|
|
_category.description 'A third simple test category'
|
|
_category.id cat_3
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_3.id'
|
|
save_
|
|
|
|
save__cat_3.id
|
|
_item.name '_cat_3.id'
|
|
_item.category_id cat_3
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_3.name
|
|
_item.name '_cat_3.name'
|
|
_item.category_id cat_3
|
|
_item.mandatory_code yes
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_3.num
|
|
_item.name '_cat_3.num'
|
|
_item.category_id cat_3
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
loop_
|
|
_pdbx_item_linked_group_list.parent_category_id
|
|
_pdbx_item_linked_group_list.link_group_id
|
|
_pdbx_item_linked_group_list.parent_name
|
|
_pdbx_item_linked_group_list.child_name
|
|
_pdbx_item_linked_group_list.child_category_id
|
|
cat_1 1 '_cat_1.name' '_cat_2.name' cat_2
|
|
cat_2 1 '_cat_2.name' '_cat_3.name' cat_3
|
|
cat_2 1 '_cat_2.num' '_cat_3.num' cat_3
|
|
|
|
)";
|
|
|
|
struct membuf : public std::streambuf
|
|
{
|
|
membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
|
|
|
|
std::istream is_dict(&buffer);
|
|
|
|
cif::validator validator(is_dict);
|
|
|
|
cif::file f;
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
const char data[] = R"(
|
|
data_test
|
|
loop_
|
|
_cat_1.id
|
|
_cat_1.name
|
|
_cat_1.desc
|
|
1 aap Aap
|
|
2 noot Noot
|
|
3 mies Mies
|
|
|
|
loop_
|
|
_cat_2.id
|
|
_cat_2.name
|
|
_cat_2.num
|
|
_cat_2.desc
|
|
1 aap 1 'Een dier'
|
|
2 aap 2 'Een andere aap'
|
|
3 noot 1 'walnoot bijvoorbeeld'
|
|
|
|
loop_
|
|
_cat_3.id
|
|
_cat_3.name
|
|
_cat_3.num
|
|
1 aap 1
|
|
2 aap 2
|
|
)";
|
|
|
|
using namespace cif::literals;
|
|
|
|
struct data_membuf : public std::streambuf
|
|
{
|
|
data_membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
|
|
|
std::istream is_data(&data_buffer);
|
|
f.load(is_data);
|
|
f.front().set_validator(&validator);
|
|
|
|
auto &cat1 = f.front()["cat_1"];
|
|
auto &cat2 = f.front()["cat_2"];
|
|
auto &cat3 = f.front()["cat_3"];
|
|
|
|
// some parent/child tests
|
|
|
|
// find all children in cat2 for the row with id == 1 in cat1
|
|
auto rs1 = cat1.get_children(cat1.find1("id"_key == 1), cat2);
|
|
CHECK(rs1.size() == 2);
|
|
|
|
auto rs2 = cat1.get_children(cat1.find1("id"_key == 2), cat2);
|
|
CHECK(rs2.size() == 1);
|
|
|
|
auto rs3 = cat1.get_children(cat1.find1("id"_key == 3), cat2);
|
|
CHECK(rs3.size() == 0);
|
|
|
|
// finding parents
|
|
auto rs4 = cat2.get_parents(cat2.find1("id"_key == 1), cat1);
|
|
CHECK(rs4.size() == 1);
|
|
|
|
auto rs5 = cat3.get_parents(cat3.find1("id"_key == 1), cat2);
|
|
CHECK(rs5.size() == 1);
|
|
|
|
// This link is not defined:
|
|
auto rs6 = cat3.get_parents(cat3.find1("id"_key == 1), cat1);
|
|
CHECK(rs6.size() == 0);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("reading_file_1")
|
|
{
|
|
std::istringstream is("Hello, world!");
|
|
|
|
cif::file file;
|
|
CHECK_THROWS_AS(file.load(is), std::runtime_error);
|
|
}
|
|
|
|
TEST_CASE("parser_test_1")
|
|
{
|
|
auto data1 = R"(
|
|
data_QM
|
|
_test.text ??
|
|
)"_cf;
|
|
|
|
auto &db1 = data1.front();
|
|
auto &test1 = db1["test"];
|
|
|
|
CHECK(test1.size() == 1);
|
|
|
|
for (auto r : test1)
|
|
{
|
|
auto text = r.get<std::string>("text");
|
|
CHECK(text == "??");
|
|
}
|
|
|
|
std::stringstream ss;
|
|
data1.save(ss);
|
|
|
|
auto data2 = cif::file(ss);
|
|
|
|
auto &db2 = data2.front();
|
|
auto &test2 = db2["test"];
|
|
|
|
CHECK(test2.size() == 1);
|
|
|
|
for (auto r : test2)
|
|
{
|
|
auto text = r.get<std::string>("text");
|
|
CHECK(text == "??");
|
|
}
|
|
}
|
|
|
|
TEST_CASE("output_test_1")
|
|
{
|
|
auto data1 = R"(
|
|
data_Q
|
|
loop_
|
|
_test.text
|
|
stop_the_crap
|
|
'and stop_ this too'
|
|
'data_dinges'
|
|
blablaglobal_bla
|
|
boo.data_.whatever
|
|
'data_.whatever'
|
|
'stop_'
|
|
'loop_'
|
|
'global_'
|
|
'_with.leading_underscore'
|
|
)"_cf;
|
|
|
|
auto &db1 = data1.front();
|
|
auto &test1 = db1["test"];
|
|
|
|
struct T
|
|
{
|
|
const char *s;
|
|
bool q;
|
|
} kS[] = {
|
|
{ "stop_the_crap", true },
|
|
{ "and stop_ this too", false },
|
|
{ "data_dinges", false },
|
|
{ "blablaglobal_bla", true },
|
|
{ "boo.data_.whatever", true },
|
|
{ "data_.whatever", false },
|
|
{ "stop_", false },
|
|
{ "loop_", false },
|
|
{ "global_", false },
|
|
{ "_with.leading_underscore", false }
|
|
};
|
|
|
|
CHECK(test1.size() == sizeof(kS) / sizeof(T));
|
|
|
|
std::size_t i = 0;
|
|
for (auto r : test1)
|
|
{
|
|
auto text = r.get<std::string>("text");
|
|
CHECK(text == kS[i].s);
|
|
CHECK(cif::sac_parser::is_unquoted_string(kS[i].s) == kS[i].q);
|
|
++i;
|
|
}
|
|
|
|
std::stringstream ss;
|
|
data1.save(ss);
|
|
|
|
auto data2 = cif::file(ss);
|
|
|
|
auto &db2 = data2.front();
|
|
auto &test2 = db2["test"];
|
|
|
|
CHECK(test2.size() == sizeof(kS) / sizeof(T));
|
|
|
|
i = 0;
|
|
for (auto r : test2)
|
|
{
|
|
auto text = r.get<std::string>("text");
|
|
CHECK(text == kS[i++].s);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("output_test_2")
|
|
{
|
|
auto data1 = R"(
|
|
data_Q
|
|
loop_
|
|
_test.text
|
|
;A very, very loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line
|
|
;
|
|
;A line with a newline, look:
|
|
There it was!
|
|
;
|
|
)"_cf;
|
|
|
|
auto &db1 = data1.front();
|
|
auto &test1 = db1["test"];
|
|
|
|
struct T
|
|
{
|
|
const char *s;
|
|
bool q;
|
|
} kS[] = {
|
|
{ "A very, very loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line", false },
|
|
{ R"(A line with a newline, look:
|
|
There it was!)",
|
|
false }
|
|
};
|
|
|
|
CHECK(test1.size() == sizeof(kS) / sizeof(T));
|
|
|
|
std::size_t i = 0;
|
|
for (auto r : test1)
|
|
{
|
|
auto text = r.get<std::string>("text");
|
|
CHECK(text == kS[i].s);
|
|
CHECK(cif::sac_parser::is_unquoted_string(kS[i].s) == kS[i].q);
|
|
++i;
|
|
}
|
|
|
|
std::stringstream ss;
|
|
data1.save(ss);
|
|
|
|
auto data2 = cif::file(ss);
|
|
|
|
auto &db2 = data2.front();
|
|
auto &test2 = db2["test"];
|
|
|
|
CHECK(test2.size() == sizeof(kS) / sizeof(T));
|
|
|
|
i = 0;
|
|
for (auto r : test2)
|
|
{
|
|
auto text = r.get<std::string>("text");
|
|
CHECK(text == kS[i++].s);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("trim_test")
|
|
{
|
|
CHECK(cif::trim_copy("aap") == "aap");
|
|
CHECK(cif::trim_copy(" aap") == "aap");
|
|
CHECK(cif::trim_copy(" aap ") == "aap");
|
|
CHECK(cif::trim_copy("aap ") == "aap");
|
|
CHECK(cif::trim_copy(" aap ") == "aap");
|
|
|
|
CHECK(cif::trim_left_copy("aap") == "aap");
|
|
CHECK(cif::trim_left_copy(" aap") == "aap");
|
|
CHECK(cif::trim_left_copy(" aap ") == "aap ");
|
|
CHECK(cif::trim_left_copy("aap ") == "aap ");
|
|
CHECK(cif::trim_left_copy("aap ") == "aap ");
|
|
|
|
CHECK(cif::trim_right_copy("aap") == "aap");
|
|
CHECK(cif::trim_right_copy(" aap") == " aap");
|
|
CHECK(cif::trim_right_copy(" aap ") == " aap");
|
|
CHECK(cif::trim_right_copy("aap ") == "aap");
|
|
CHECK(cif::trim_right_copy(" aap ") == " aap");
|
|
|
|
std::string s;
|
|
|
|
s = "aap";
|
|
cif::trim(s);
|
|
CHECK(s == "aap");
|
|
s = " aap";
|
|
cif::trim(s);
|
|
CHECK(s == "aap");
|
|
s = " aap ";
|
|
cif::trim(s);
|
|
CHECK(s == "aap");
|
|
s = "aap ";
|
|
cif::trim(s);
|
|
CHECK(s == "aap");
|
|
s = " aap ";
|
|
cif::trim(s);
|
|
CHECK(s == "aap");
|
|
|
|
s = "aap";
|
|
cif::trim_left(s);
|
|
CHECK(s == "aap");
|
|
s = " aap";
|
|
cif::trim_left(s);
|
|
CHECK(s == "aap");
|
|
s = " aap ";
|
|
cif::trim_left(s);
|
|
CHECK(s == "aap ");
|
|
s = "aap ";
|
|
cif::trim_left(s);
|
|
CHECK(s == "aap ");
|
|
s = "aap ";
|
|
cif::trim_left(s);
|
|
CHECK(s == "aap ");
|
|
|
|
s = "aap";
|
|
cif::trim_right(s);
|
|
CHECK(s == "aap");
|
|
s = " aap";
|
|
cif::trim_right(s);
|
|
CHECK(s == " aap");
|
|
s = " aap ";
|
|
cif::trim_right(s);
|
|
CHECK(s == " aap");
|
|
s = "aap ";
|
|
cif::trim_right(s);
|
|
CHECK(s == "aap");
|
|
s = " aap ";
|
|
cif::trim_right(s);
|
|
CHECK(s == " aap");
|
|
}
|
|
|
|
TEST_CASE("split_test")
|
|
{
|
|
std::vector<std::string_view> v, t;
|
|
|
|
v = cif::split<>("aap;noot;mies", ";");
|
|
t = std::vector<std::string_view>{ "aap", "noot", "mies" };
|
|
|
|
CHECK(v == t);
|
|
|
|
v = cif::split("aap;noot,mies", ";,");
|
|
// t = std::vector<std::string>{ "aap", "noot", "mies" };
|
|
|
|
CHECK(v == t);
|
|
|
|
v = cif::split(";aap;noot,mies;", ";,");
|
|
t = std::vector<std::string_view>{ "", "aap", "noot", "mies", "" };
|
|
|
|
CHECK(v == t);
|
|
|
|
v = cif::split(";aap;noot,mies;", ";,", true);
|
|
t = std::vector<std::string_view>{ "aap", "noot", "mies" };
|
|
|
|
CHECK(v == t);
|
|
}
|
|
|
|
TEST_CASE("join_test")
|
|
{
|
|
CHECK(cif::join(std::vector<std::string>{ "aap" }, ", ") == "aap");
|
|
CHECK(cif::join(std::vector<std::string>{ "aap", "noot" }, ", ") == "aap, noot");
|
|
CHECK(cif::join(std::vector<std::string>{ "aap", "noot", "mies" }, ", ") == "aap, noot, mies");
|
|
}
|
|
|
|
TEST_CASE("replace_all_test")
|
|
{
|
|
std::string s("aap, noot, mies");
|
|
cif::replace_all(s, ", ", ",");
|
|
CHECK(s == "aap,noot,mies");
|
|
|
|
cif::replace_all(s, ",", ", ");
|
|
CHECK(s == "aap, noot, mies");
|
|
|
|
cif::replace_all(s, ", ", ", ");
|
|
CHECK(s == "aap, noot, mies");
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("reorder_test")
|
|
{
|
|
|
|
const char dict[] = R"(
|
|
data_test_dict.dic
|
|
_datablock.id test_dict.dic
|
|
_datablock.description
|
|
;
|
|
A test dictionary
|
|
;
|
|
_dictionary.title test_dict.dic
|
|
_dictionary.datablock_id test_dict.dic
|
|
_dictionary.version 1.0
|
|
|
|
loop_
|
|
_item_type_list.code
|
|
_item_type_list.primitive_code
|
|
_item_type_list.construct
|
|
_item_type_list.detail
|
|
code char
|
|
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
|
|
; code item types/single words ...
|
|
;
|
|
text char
|
|
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
|
|
; text item types / multi-line text ...
|
|
;
|
|
int numb
|
|
'[+-]?[0-9]+'
|
|
; int item types are the subset of numbers that are the negative
|
|
or positive integers.
|
|
;
|
|
|
|
save_cat_1
|
|
_category.description 'A simple test category'
|
|
_category.id cat_1
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_1.id'
|
|
|
|
save_
|
|
|
|
save__cat_1.id
|
|
_item.name '_cat_1.id'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_aliases.dictionary cif_core.dic
|
|
_item_aliases.version 2.0.1
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_1.name
|
|
_item.name '_cat_1.name'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_aliases.dictionary cif_core.dic
|
|
_item_aliases.version 2.0.1
|
|
_item_type.code text
|
|
save_
|
|
)";
|
|
|
|
struct membuf : public std::streambuf
|
|
{
|
|
membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
|
|
|
|
std::istream is_dict(&buffer);
|
|
|
|
cif::validator validator(is_dict);
|
|
|
|
cif::file f;
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
const char data[] = R"(
|
|
data_test
|
|
loop_
|
|
_cat_1.id
|
|
_cat_1.name
|
|
2 Noot
|
|
1 Aap
|
|
3 Mies
|
|
)";
|
|
|
|
struct data_membuf : public std::streambuf
|
|
{
|
|
data_membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
|
|
|
std::istream is_data(&data_buffer);
|
|
f.load(is_data);
|
|
f.front().set_validator(&validator);
|
|
|
|
CHECK(f.is_valid());
|
|
|
|
auto &cat1 = f.front()["cat_1"];
|
|
cat1.reorder_by_index();
|
|
|
|
int n = 1;
|
|
|
|
const char *ts[] = { "Aap", "Noot", "Mies" };
|
|
|
|
for (const auto &[id, name] : cat1.rows<int, std::string>("id", "name"))
|
|
{
|
|
CHECK(id == n);
|
|
CHECK(name == ts[n - 1]);
|
|
++n;
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("audit_conform_test")
|
|
{
|
|
|
|
const char dict[] = R"(
|
|
data_test_dict.dic
|
|
_datablock.id test_dict.dic
|
|
_datablock.description
|
|
;
|
|
A test dictionary
|
|
;
|
|
_dictionary.title test_dict.dic
|
|
_dictionary.datablock_id test_dict.dic
|
|
_dictionary.version 1.0
|
|
|
|
loop_
|
|
_item_type_list.code
|
|
_item_type_list.primitive_code
|
|
_item_type_list.construct
|
|
_item_type_list.detail
|
|
code char
|
|
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
|
|
; code item types/single words ...
|
|
;
|
|
text char
|
|
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
|
|
; text item types / multi-line text ...
|
|
;
|
|
int numb
|
|
'[+-]?[0-9]+'
|
|
; int item types are the subset of numbers that are the negative
|
|
or positive integers.
|
|
;
|
|
|
|
###################
|
|
## AUDIT_CONFORM ##
|
|
###################
|
|
|
|
save_audit_conform
|
|
_category.description
|
|
; Data items in the AUDIT_CONFORM category describe the
|
|
dictionary versions against which the data names appearing in
|
|
the current data block are conformant.
|
|
;
|
|
_category.id audit_conform
|
|
_category.mandatory_code no
|
|
loop_
|
|
_category_key.name '_audit_conform.dict_name'
|
|
'_audit_conform.dict_version'
|
|
loop_
|
|
_category_group.id 'inclusive_group'
|
|
'audit_group'
|
|
loop_
|
|
_category_examples.detail
|
|
_category_examples.case
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
;
|
|
Example 1 - any file conforming to the current CIF core dictionary.
|
|
;
|
|
;
|
|
_audit_conform.dict_name cif_core.dic
|
|
_audit_conform.dict_version 2.3.1
|
|
_audit_conform.dict_location
|
|
ftp://ftp.iucr.org/pub/cif_core.2.3.1.dic
|
|
;
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
save_
|
|
|
|
save__audit_conform.dict_location
|
|
_item_description.description
|
|
; A file name or uniform resource locator (URL) for the
|
|
dictionary to which the current data block conforms.
|
|
;
|
|
_item.name '_audit_conform.dict_location'
|
|
_item.category_id audit_conform
|
|
_item.mandatory_code no
|
|
_item_aliases.alias_name '_audit_conform_dict_location'
|
|
_item_aliases.dictionary cif_core.dic
|
|
_item_aliases.version 2.0.1
|
|
_item_type.code text
|
|
save_
|
|
|
|
save__audit_conform.dict_name
|
|
_item_description.description
|
|
; The string identifying the highest-level dictionary defining
|
|
data names used in this file.
|
|
;
|
|
_item.name '_audit_conform.dict_name'
|
|
_item.category_id audit_conform
|
|
_item.mandatory_code yes
|
|
_item_aliases.alias_name '_audit_conform_dict_name'
|
|
_item_aliases.dictionary cif_core.dic
|
|
_item_aliases.version 2.0.1
|
|
_item_type.code text
|
|
save_
|
|
|
|
save__audit_conform.dict_version
|
|
_item_description.description
|
|
; The version number of the dictionary to which the current
|
|
data block conforms.
|
|
;
|
|
_item.name '_audit_conform.dict_version'
|
|
_item.category_id audit_conform
|
|
_item.mandatory_code yes
|
|
_item_aliases.alias_name '_audit_conform_dict_version'
|
|
_item_aliases.dictionary cif_core.dic
|
|
_item_aliases.version 2.0.1
|
|
_item_type.code text
|
|
save_
|
|
|
|
save_cat_1
|
|
_category.description 'A simple test category'
|
|
_category.id cat_1
|
|
_category.mandatory_code no
|
|
_category_key.name '_cat_1.id'
|
|
|
|
save_
|
|
|
|
save__cat_1.id
|
|
_item.name '_cat_1.id'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_aliases.dictionary cif_core.dic
|
|
_item_aliases.version 2.0.1
|
|
_item_type.code code
|
|
save_
|
|
|
|
save__cat_1.name
|
|
_item.name '_cat_1.name'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_aliases.dictionary cif_core.dic
|
|
_item_aliases.version 2.0.1
|
|
_item_type.code text
|
|
save_
|
|
)";
|
|
|
|
struct membuf : public std::streambuf
|
|
{
|
|
membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
|
|
|
|
std::istream is_dict(&buffer);
|
|
|
|
auto &validator = cif::validator_factory::instance().add(cif::validator(is_dict));
|
|
|
|
cif::file f;
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
const char data[] = R"(
|
|
data_test
|
|
#
|
|
_audit_conform.dict_name test_dict.dic
|
|
_audit_conform.dict_version 1.0
|
|
#
|
|
loop_
|
|
_cat_1.id
|
|
_cat_1.name
|
|
2 Noot
|
|
1 Aap
|
|
3 Mies
|
|
)";
|
|
|
|
struct data_membuf : public std::streambuf
|
|
{
|
|
data_membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
|
|
|
std::istream is_data(&data_buffer);
|
|
f.load(is_data);
|
|
f.front().set_validator(&validator);
|
|
|
|
CHECK(f.is_valid());
|
|
|
|
std::stringstream ss;
|
|
ss << f;
|
|
|
|
cif::file f2(ss);
|
|
CHECK(f2.empty() == false);
|
|
f2.front().load_dictionary();
|
|
CHECK(f2.is_valid());
|
|
|
|
auto &audit_conform = f2.front()["audit_conform"];
|
|
CHECK(audit_conform.front()["dict_name"].get<std::string>() == "test_dict.dic");
|
|
CHECK(audit_conform.front()["dict_version"].get<float>() == 1.0);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("ix_op_1")
|
|
{
|
|
const char dict[] = R"(
|
|
data_test_dict.dic
|
|
_datablock.id test_dict.dic
|
|
_datablock.description
|
|
;
|
|
A test dictionary
|
|
;
|
|
_dictionary.title test_dict.dic
|
|
_dictionary.datablock_id test_dict.dic
|
|
_dictionary.version 1.0
|
|
|
|
loop_
|
|
_item_type_list.code
|
|
_item_type_list.primitive_code
|
|
_item_type_list.construct
|
|
code char
|
|
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
|
|
|
|
text char
|
|
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
|
|
|
|
int numb
|
|
'[+-]?[0-9]+'
|
|
|
|
save_cat_1
|
|
_category.description 'A simple test category'
|
|
_category.id cat_1
|
|
_category.mandatory_code yes
|
|
loop_
|
|
_category_key.name '_cat_1.id'
|
|
'_cat_1.id_2'
|
|
save_
|
|
|
|
save__cat_1.id
|
|
_item.name '_cat_1.id'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code yes
|
|
_item_type.code int
|
|
save_
|
|
|
|
save__cat_1.id_2
|
|
_item.name '_cat_1.id_2'
|
|
_item.category_id cat_1
|
|
_item.mandatory_code no
|
|
_item_type.code int
|
|
save_
|
|
)";
|
|
|
|
struct membuf : public std::streambuf
|
|
{
|
|
membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
|
|
|
|
std::istream is_dict(&buffer);
|
|
|
|
cif::validator validator(is_dict);
|
|
|
|
cif::file f;
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
const char data[] = R"(
|
|
data_test
|
|
loop_
|
|
_cat_1.id
|
|
_cat_1.id_2
|
|
1 10
|
|
2 20
|
|
3 ?
|
|
)";
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
struct data_membuf : public std::streambuf
|
|
{
|
|
data_membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
|
|
|
std::istream is_data(&data_buffer);
|
|
f.load(is_data);
|
|
f.front().set_validator(&validator);
|
|
|
|
auto &cat1 = f.front()["cat_1"];
|
|
|
|
using key_type = cif::category::key_type;
|
|
using test_tuple_type = std::tuple<key_type, bool>;
|
|
|
|
test_tuple_type TESTS[] = {
|
|
{ { { "id", 1 }, { "id_2", 10 } }, true },
|
|
{ { { "id_2", 10 }, { "id", 1 } }, true },
|
|
{ { { "id", 1 }, { "id_2", 20 } }, false },
|
|
{ { { "id", 3 }, { "id_2", nullptr } }, true },
|
|
};
|
|
|
|
for (const auto &[key, test] : TESTS)
|
|
CHECK((bool)cat1[key] == test);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("cifv1_0_1")
|
|
{
|
|
auto f = R"(data_TEST
|
|
#
|
|
loop_
|
|
_id
|
|
_name
|
|
1 aap
|
|
2 noot
|
|
3 mies
|
|
4 ?
|
|
5 .
|
|
)"_cf;
|
|
|
|
auto &db = f.front();
|
|
|
|
auto &cat = db[""];
|
|
|
|
for (auto r : cat)
|
|
{
|
|
int id;
|
|
std::optional<std::string> name;
|
|
|
|
cif::tie(id, name) = r.get("id", "name");
|
|
|
|
switch (id)
|
|
{
|
|
case 1:
|
|
REQUIRE(name.has_value());
|
|
CHECK(*name == "aap"); // NOLINT
|
|
break;
|
|
case 2:
|
|
REQUIRE(name.has_value());
|
|
CHECK(*name == "noot"); // NOLINT
|
|
break;
|
|
case 3:
|
|
REQUIRE(name.has_value());
|
|
CHECK(*name == "mies"); // NOLINT
|
|
break;
|
|
default: CHECK(name.has_value() == false);
|
|
}
|
|
}
|
|
|
|
std::stringstream ss;
|
|
ss << db;
|
|
|
|
auto f2 = cif::file(ss);
|
|
auto &db2 = f2.front();
|
|
|
|
CHECK(db == db2);
|
|
}
|
|
|
|
// TEST_CASE("cifv1_0_2")
|
|
// {
|
|
// CHECK_THROWS_AS(R"(data_TEST
|
|
// #
|
|
// _version 1.0
|
|
// loop_
|
|
// _id
|
|
// _name
|
|
// 1 aap
|
|
// 2 noot
|
|
// 3 mies
|
|
// 4 ?
|
|
// 5 .
|
|
// )"_cf, cif::parse_error);
|
|
// }
|
|
|
|
TEST_CASE("cifv1_0_3")
|
|
{
|
|
auto f = R"(data_TEST
|
|
#
|
|
_version 1.0
|
|
_date today
|
|
)"_cf;
|
|
|
|
auto &db = f.front();
|
|
|
|
auto &cat = db[""];
|
|
CHECK(not cat.empty());
|
|
|
|
auto r = cat.front();
|
|
CHECK(r["version"].get<float>() == 1.0);
|
|
CHECK(r["date"].get<std::string>() == "today");
|
|
|
|
std::stringstream ss;
|
|
ss << db;
|
|
|
|
auto f2 = cif::file(ss);
|
|
auto &db2 = f2.front();
|
|
|
|
CHECK(db == db2);
|
|
}
|
|
|
|
TEST_CASE("find1_opt_1")
|
|
{
|
|
using namespace cif::literals;
|
|
using namespace std::literals;
|
|
|
|
auto f = R"(data_TEST
|
|
#
|
|
loop_
|
|
_test.id
|
|
_test.name
|
|
_test.value
|
|
1 aap 1.0
|
|
2 noot 1.1
|
|
3 mies 1.2
|
|
)"_cf;
|
|
|
|
auto &db = f.front();
|
|
auto &test = db["test"];
|
|
|
|
auto v = test.find1<std::optional<float>>("id"_key == 1, "value");
|
|
CHECK(v.has_value());
|
|
CHECK(*v == 1.0f); // NOLINT(bugprone-unchecked-optional-access)
|
|
|
|
v = test.find1<std::optional<float>>("id"_key == 4, "value");
|
|
CHECK(v.has_value() == false);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("compound_test_1")
|
|
{
|
|
cif::compound_factory::instance().push_dictionary(gTestDir / "REA_v2.cif");
|
|
auto compound = cif::compound_factory::instance().create("REA_v2");
|
|
CHECK(compound != nullptr);
|
|
CHECK(cif::iequals(compound->id(), "REA_v2"));
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("pdb_parser_test_1")
|
|
{
|
|
char k1CBS[] = R"(HEADER RETINOIC-ACID TRANSPORT 28-SEP-94 1CBS
|
|
TITLE CRYSTAL STRUCTURE OF CELLULAR RETINOIC-ACID-BINDING
|
|
TITLE 2 PROTEINS I AND II IN COMPLEX WITH ALL-TRANS-RETINOIC ACID
|
|
TITLE 3 AND A SYNTHETIC RETINOID
|
|
COMPND MOL_ID: 1;
|
|
COMPND 2 MOLECULE: CELLULAR RETINOIC ACID BINDING PROTEIN TYPE II;
|
|
COMPND 3 CHAIN: A;
|
|
COMPND 4 ENGINEERED: YES
|
|
SOURCE MOL_ID: 1;
|
|
SOURCE 2 ORGANISM_SCIENTIFIC: HOMO SAPIENS;
|
|
SOURCE 3 ORGANISM_COMMON: HUMAN;
|
|
SOURCE 4 ORGANISM_TAXID: 9606;
|
|
SOURCE 5 CELL_LINE: BL21;
|
|
SOURCE 6 GENE: HUMAN CRABP-II;
|
|
SOURCE 7 EXPRESSION_SYSTEM: ESCHERICHIA COLI BL21(DE3);
|
|
SOURCE 8 EXPRESSION_SYSTEM_TAXID: 469008;
|
|
SOURCE 9 EXPRESSION_SYSTEM_STRAIN: BL21 (DE3);
|
|
SOURCE 10 EXPRESSION_SYSTEM_PLASMID: PET-3A
|
|
KEYWDS RETINOIC-ACID TRANSPORT
|
|
EXPDTA X-RAY DIFFRACTION
|
|
AUTHOR G.J.KLEYWEGT,T.BERGFORS,T.A.JONES
|
|
ATOM 1 N PRO A 1 16.979 13.301 44.555 1.00 30.05 N
|
|
ATOM 2 CA PRO A 1 18.150 13.525 43.680 1.00 28.82 C
|
|
ATOM 3 C PRO A 1 18.656 14.966 43.784 1.00 26.59 C
|
|
ATOM 4 O PRO A 1 17.890 15.889 44.078 1.00 26.84 O
|
|
ATOM 5 CB PRO A 1 17.678 13.270 42.255 1.00 29.24 C
|
|
ATOM 6 CG PRO A 1 16.248 13.734 42.347 1.00 29.29 C
|
|
ATOM 7 CD PRO A 1 15.762 13.216 43.724 1.00 30.71 C)";
|
|
|
|
struct membuf : public std::streambuf
|
|
{
|
|
membuf(char *text, std::size_t length)
|
|
{
|
|
this->setg(text, text, text + length);
|
|
}
|
|
} buffer(k1CBS, sizeof(k1CBS) - 1);
|
|
|
|
std::istream is(&buffer);
|
|
|
|
auto f = cif::pdb::read(is);
|
|
CHECK(f.is_valid());
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("compound_not_found_test_1")
|
|
{
|
|
auto cmp = cif::compound_factory::instance().create("&&&");
|
|
CHECK(cmp == nullptr);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// PDB2CIF tests
|
|
|
|
TEST_CASE("pdb2cif_formula_weight")
|
|
{
|
|
cif::compound_factory::instance().push_dictionary(gTestDir / "REA.cif");
|
|
|
|
cif::file a = cif::pdb::read(gTestDir / "pdb1cbs.ent.gz");
|
|
|
|
auto fw = a.front()["entity"].find1<float>(cif::key("id") == 1, "formula_weight");
|
|
CHECK(std::abs(fw - 15581.802f) < 0.1f);
|
|
|
|
fw = a.front()["entity"].find1<float>(cif::key("id") == 2, "formula_weight");
|
|
CHECK(fw == 300.435f);
|
|
|
|
fw = a.front()["entity"].find1<float>(cif::key("id") == 3, "formula_weight");
|
|
CHECK(fw == 18.015f);
|
|
}
|
|
|
|
// // --------------------------------------------------------------------
|
|
|
|
// TEST_CASE("update_values_with_provider")
|
|
// {
|
|
|
|
// }
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
TEST_CASE("io-test-1")
|
|
{
|
|
cif::category cat("test");
|
|
cat.emplace({ { "v1", { 0.0, 3 } } });
|
|
|
|
std::ostringstream os;
|
|
os << cat;
|
|
|
|
CHECK(os.str() == R"(_test.v1 0.000
|
|
#
|
|
)");
|
|
}
|
|
|
|
TEST_CASE("io-test-2")
|
|
{
|
|
auto data = R"(data_test
|
|
loop_
|
|
_test.v1
|
|
1.000
|
|
0.000
|
|
)"_cf;
|
|
|
|
std::ostringstream os;
|
|
os << data;
|
|
|
|
CHECK(os.str() == R"(data_test
|
|
#
|
|
loop_
|
|
_test.v1
|
|
1.000
|
|
0.000
|
|
#
|
|
)");
|
|
}
|
|
|
|
TEST_CASE("io-test-3")
|
|
{
|
|
auto data = R"(data_test
|
|
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_atom_id
|
|
_atom_site.auth_comp_id
|
|
_atom_site.auth_seq_id
|
|
_atom_site.auth_asym_id
|
|
_atom_site.pdbx_PDB_model_num
|
|
HETATM 1 O O . HOH A 1 . ? 10.518 -1.781 0 1 37.22 ? O HOH 1 D 1
|
|
)"_cf;
|
|
|
|
auto &db = data.front();
|
|
db.load_dictionary("mmcif_pdbx.dic");
|
|
|
|
auto row = db["atom_site"].front();
|
|
const auto &[x, y, z, id, label_asym_id, auth_asym_id, auth_seq_id] = row.get<float, float, float, std::string, std::string, std::string, int>("cartn_x", "cartn_y", "cartn_z", "id", "label_asym_id", "auth_asym_id", "auth_seq_id");
|
|
|
|
cif::mm::structure s(data);
|
|
s.create_water(row);
|
|
|
|
std::ostringstream os;
|
|
os << db["atom_site"];
|
|
|
|
CHECK(os.str() == R"(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_atom_id
|
|
_atom_site.auth_comp_id
|
|
_atom_site.auth_seq_id
|
|
_atom_site.auth_asym_id
|
|
_atom_site.pdbx_PDB_model_num
|
|
HETATM 1 O O . HOH A 1 . ? 10.518 -1.781 0 1 37.22 ? O HOH 1 D 1
|
|
HETATM 2 O O . HOH A 1 . ? 10.518 -1.781 0 1 37.22 ? O HOH 2 D 1
|
|
#
|
|
)");
|
|
}
|
|
|
|
|
|
|