/* Copyright (c) 2006-2018 Elmar Pruesse This file is part of SINA. SINA is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SINA is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SINA. If not, see . Additional permission under GNU GPL version 3 section 7 If you modify SINA, or any covered work, by linking or combining it with components of ARB (or a modified version of that software), containing parts covered by the terms of the ARB-public-library-license, the licensors of SINA grant you additional permission to convey the resulting work. Corresponding Source for a non-source form of such a combination shall include the source code for the parts of ARB used as well as that of the covered work. */ #include "../query_arb.h" #include "../tempfile.h" #include "../log.h" // ARB needs either DEBUG or NDEBUG defined #ifdef DEBUG # define typeof __typeof__ #else # ifndef NDEBUG # define NDEBUG 1 # endif #endif #include #define BOOST_TEST_MODULE query_arb_test #include namespace utf = boost::unit_test; #include namespace bdata = utf::data; #include namespace fs = boost::filesystem; #include using namespace sina; struct GlobalFixture { static GlobalFixture*& instance() { static GlobalFixture* inst{nullptr}; return inst; } GlobalFixture() { instance() = this; int argc = boost::unit_test::framework::master_test_suite().argc; if (argc != 2) { throw std::runtime_error("Need exactly 1 argument: the reference arb file"); } char** argv = boost::unit_test::framework::master_test_suite().argv; query_arb* ref = query_arb::getARBDB(argv[1]); query_arb* tmp = query_arb::getARBDB(small_arb_path()); _ids = ref->getSequenceNames(); std::sort(_ids.begin(), _ids.end()); std::srand(1234); std::random_shuffle(_ids.begin(), _ids.end()); _ids.resize(n_seq); _ids[0] = "MyoSeoul"; for (auto id : _ids) { tmp->copySequence(*ref, id, false); } tmp->save(); query_arb::closeOpenARBDBs(); } ~GlobalFixture() { instance() = nullptr; } const TempFile& small_arb_path() const { return _small_arb_path; } const std::vector& ids() const { return _ids; } TempFile _small_arb_path; std::vector _ids; const size_t n_seq{50}; }; struct CaseFixture { CaseFixture() {} ~CaseFixture() { query_arb::closeOpenARBDBs(); } const GlobalFixture& globalFixture() const { return *GlobalFixture::instance(); } query_arb* tmparb() { if (_tmparb == nullptr) { _tmparb = query_arb::getARBDB(tmpfile); } return _tmparb; } query_arb* smallarb() { if (_smallarb == nullptr) { _smallarb = query_arb::getARBDB(globalFixture().small_arb_path()); } return _smallarb; } const std::vector& ids() const { return globalFixture().ids(); } TempFile tmpfile; query_arb *_tmparb{nullptr}, *_smallarb{nullptr}; }; struct what_starts_with { explicit what_starts_with(const std::string& prefix) : _prefix(prefix) {} bool operator()(const std::exception& e) const { return std::string(e.what()).rfind(_prefix, 0) == 0; } std::string _prefix; }; BOOST_GLOBAL_FIXTURE(GlobalFixture); BOOST_FIXTURE_TEST_SUITE(query_arb_test, CaseFixture); BOOST_AUTO_TEST_CASE(new_file) { query_arb* arb = tmparb(); arb->save(); fs::exists(tmpfile); query_arb::closeOpenARBDBs(); fs::remove(tmpfile); arb = query_arb::getARBDB(tmpfile); arb->save(); fs::exists(tmpfile); } BOOST_AUTO_TEST_CASE(cache) { query_arb *arb = smallarb(); arb->loadCache(); std::vector cache = arb->getCacheContents(); BOOST_CHECK_EQUAL(cache.size(), globalFixture().n_seq); for (auto* c: cache) { const cseq& d = arb->getCseq(c->getName()); BOOST_CHECK_EQUAL(c, &d); } } BOOST_AUTO_TEST_CASE(empty_filename) { BOOST_CHECK_EXCEPTION( query_arb::getARBDB(""), query_arb_exception, what_starts_with("Empty ARB database") ); } BOOST_AUTO_TEST_CASE(unable_to_open) { TempFile notAnArbFile; { boost::filesystem::ofstream out(notAnArbFile); out << "Nothing" << std::endl; } BOOST_CHECK_EXCEPTION( query_arb::getARBDB(notAnArbFile), query_arb_exception, what_starts_with("Unable to open") ); } BOOST_AUTO_TEST_CASE(unable_to_save) { query_arb *arb = tmparb(); TempFile write_protected; { boost::filesystem::ofstream out(write_protected); } boost::filesystem::permissions( write_protected, boost::filesystem::owner_read); std::ostringstream oss; auto ostream_sink = std::make_shared (oss); ostream_sink->set_level(spdlog::level::err); Log::add_sink(ostream_sink); arb->saveAs(write_protected); Log::remove_sink(ostream_sink); BOOST_CHECK(oss.str().find("Error while trying to save") != std::string::npos); } BOOST_AUTO_TEST_CASE(getFileName) { query_arb *arb = smallarb(); BOOST_CHECK_EQUAL(globalFixture().small_arb_path(), arb->getFileName()); } BOOST_AUTO_TEST_CASE(getAlignmentWidth) { query_arb *arb = smallarb(); BOOST_CHECK_EQUAL(50000, arb->getAlignmentWidth()); } BOOST_AUTO_TEST_CASE(getSeqCount) { query_arb *arb = smallarb(); BOOST_CHECK_EQUAL(globalFixture().n_seq, arb->getSeqCount()); } BOOST_AUTO_TEST_CASE(read_fail) { query_arb *arb = smallarb(); BOOST_CHECK_EXCEPTION( arb->getCseq("doesnotexist"), query_arb_exception, what_starts_with("No sequence \"doesnotexist") ); } BOOST_AUTO_TEST_CASE(empty_alignment) { GBDATA* gbmain = GB_open(globalFixture().small_arb_path().path().native().c_str(), "rw"); { GB_transaction trans(gbmain); GBDATA* gbspecs = GB_search(gbmain, "species_data", GB_CREATE_CONTAINER); GBDATA* gbspec = GB_create_container(gbspecs, "species"); GBDATA* gbname = GB_create(gbspec, "name", GB_STRING); GB_write_string(gbname, "emptyspecies"); } GB_save_as(gbmain, tmpfile.path().native().c_str(), "b"); GB_close(gbmain); query_arb *arb = tmparb(); BOOST_CHECK_EXCEPTION( arb->getCseq("emptyspecies"), query_arb_exception, what_starts_with("No alignment for sequence \"emptyspecies") ); } BOOST_AUTO_TEST_CASE(read_write_ok) { query_arb *arb = smallarb(); const cseq &c = arb->getCseq(ids()[0]); cseq d = c; d.setName("new_sequence"); arb->putCseq(c); BOOST_CHECK_EQUAL(globalFixture().n_seq, arb->getSeqCount()); arb->putCseq(d); BOOST_CHECK_EQUAL(globalFixture().n_seq + 1, arb->getSeqCount()); } BOOST_AUTO_TEST_CASE(read_acc) { query_arb *arb = smallarb(); const cseq &c = arb->getCseq(ids()[0]); BOOST_CHECK_EQUAL(c.get_attr("acc", "none"), "none"); arb->loadKey(c, "acc"); BOOST_CHECK_EQUAL(c.get_attr("acc"), "DQ536403"); } BOOST_AUTO_TEST_CASE(write_acc) { query_arb *arb = smallarb(); const cseq &c = arb->getCseq(ids()[0]); cseq d = c; cseq e = c; d.set_attr("acc", "12345678"); arb->putCseq(d); arb->loadKey(e, "acc"); BOOST_CHECK_EQUAL(e.get_attr("acc"), "12345678"); d.set_attr("acc", "ABCDE"); arb->storeKey(d, "acc"); arb->loadKey(e, "acc", true); BOOST_CHECK_EQUAL(e.get_attr("acc"), "ABCDE"); } BOOST_AUTO_TEST_CASE(write_int) { query_arb *arb = smallarb(); const cseq &c = arb->getCseq(ids()[0]); cseq d = c; cseq e = c; d.set_attr("acc", 123); arb->storeKey(d, "acc"); arb->loadKey(e, "acc", true); BOOST_CHECK_EQUAL(e.get_attr("acc"), 123); } BOOST_AUTO_TEST_CASE(write_float) { query_arb *arb = smallarb(); const cseq &c = arb->getCseq(ids()[0]); cseq d = c; cseq e = c; d.set_attr("acc", 2.3f); arb->storeKey(d, "acc"); arb->loadKey(e, "acc", true); BOOST_CHECK_EQUAL(e.get_attr("acc"), 2.3f); } /* BOOST_AUTO_TEST_CASE(open_pt_db) BOOST_AUTO_TEST_CASE(arb_status) BOOST_AUTO_TEST_CASE(arb_error) */ BOOST_AUTO_TEST_SUITE_END(); // rw_csv_test /* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil fill-column:99 End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :