| 1 | /* |
|---|
| 2 | Copyright (c) 2006-2018 Elmar Pruesse <elmar.pruesse@ucdenver.edu> |
|---|
| 3 | |
|---|
| 4 | This file is part of SINA. |
|---|
| 5 | SINA is free software: you can redistribute it and/or modify it under |
|---|
| 6 | the terms of the GNU General Public License as published by the Free |
|---|
| 7 | Software Foundation, either version 3 of the License, or (at your |
|---|
| 8 | option) any later version. |
|---|
| 9 | |
|---|
| 10 | SINA is distributed in the hope that it will be useful, but WITHOUT ANY |
|---|
| 11 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|---|
| 13 | for more details. |
|---|
| 14 | |
|---|
| 15 | You should have received a copy of the GNU General Public License |
|---|
| 16 | along with SINA. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 17 | |
|---|
| 18 | Additional permission under GNU GPL version 3 section 7 |
|---|
| 19 | |
|---|
| 20 | If you modify SINA, or any covered work, by linking or combining it |
|---|
| 21 | with components of ARB (or a modified version of that software), |
|---|
| 22 | containing parts covered by the terms of the |
|---|
| 23 | ARB-public-library-license, the licensors of SINA grant you additional |
|---|
| 24 | permission to convey the resulting work. Corresponding Source for a |
|---|
| 25 | non-source form of such a combination shall include the source code |
|---|
| 26 | for the parts of ARB used as well as that of the covered work. |
|---|
| 27 | */ |
|---|
| 28 | |
|---|
| 29 | #include "../rw_csv.h" |
|---|
| 30 | #include "../tempfile.h" |
|---|
| 31 | |
|---|
| 32 | #define BOOST_TEST_MODULE rw |
|---|
| 33 | |
|---|
| 34 | #include <boost/test/unit_test.hpp> |
|---|
| 35 | namespace utf = boost::unit_test; |
|---|
| 36 | #include <boost/test/data/test_case.hpp> |
|---|
| 37 | namespace bdata = utf::data; |
|---|
| 38 | #include <boost/filesystem.hpp> |
|---|
| 39 | namespace fs = boost::filesystem; |
|---|
| 40 | #include <boost/program_options.hpp> |
|---|
| 41 | namespace po = boost::program_options; |
|---|
| 42 | |
|---|
| 43 | |
|---|
| 44 | using namespace sina; |
|---|
| 45 | |
|---|
| 46 | |
|---|
| 47 | struct Fixture { |
|---|
| 48 | fs::path model{"sina-%%%%-%%%%.csv"}; |
|---|
| 49 | std::unique_ptr<TempFile> outfile; |
|---|
| 50 | rw_csv::writer* writer{nullptr}; |
|---|
| 51 | int copy_relatives{0}; |
|---|
| 52 | std::vector<std::string> fields; |
|---|
| 53 | |
|---|
| 54 | std::string _output; |
|---|
| 55 | int _nlines{0}; |
|---|
| 56 | |
|---|
| 57 | Fixture() |
|---|
| 58 | : outfile(new TempFile(model)) |
|---|
| 59 | { |
|---|
| 60 | configure({}); |
|---|
| 61 | } |
|---|
| 62 | |
|---|
| 63 | void set_ext(const std::string& ext) { |
|---|
| 64 | outfile = std::unique_ptr<TempFile>( |
|---|
| 65 | new TempFile(fs::path("sina-%%%%-%%%%.") += ext) |
|---|
| 66 | ); |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | void write(const cseq& c) { |
|---|
| 70 | if (!writer) { |
|---|
| 71 | writer = new rw_csv::writer(*outfile, copy_relatives, fields); |
|---|
| 72 | } |
|---|
| 73 | tray t; |
|---|
| 74 | t.aligned_sequence = const_cast<cseq*>(&c); |
|---|
| 75 | (*writer)(t); |
|---|
| 76 | } |
|---|
| 77 | |
|---|
| 78 | std::string& output() { |
|---|
| 79 | if (writer) { |
|---|
| 80 | delete writer; |
|---|
| 81 | _output = outfile->load(); |
|---|
| 82 | writer = nullptr; |
|---|
| 83 | } |
|---|
| 84 | return _output; |
|---|
| 85 | } |
|---|
| 86 | |
|---|
| 87 | int nlines() { |
|---|
| 88 | auto txt = output(); |
|---|
| 89 | return std::count(txt.begin(), txt.end(), '\n'); |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | void configure(std::initializer_list<const char*> l) { |
|---|
| 93 | const char* cmd[l.size()+1]; |
|---|
| 94 | cmd[0] = "sina"; |
|---|
| 95 | int i = 1; |
|---|
| 96 | for (auto lv : l) { |
|---|
| 97 | cmd[i++] = lv; |
|---|
| 98 | } |
|---|
| 99 | po::variables_map vm; |
|---|
| 100 | po::options_description od, adv_od; |
|---|
| 101 | rw_csv::get_options_description(od, adv_od); |
|---|
| 102 | od.add(adv_od); |
|---|
| 103 | po::store( |
|---|
| 104 | po::parse_command_line(l.size()+1, cmd, od), |
|---|
| 105 | vm); |
|---|
| 106 | try { |
|---|
| 107 | po::notify(vm); |
|---|
| 108 | rw_csv::validate_vm(vm, od); |
|---|
| 109 | } catch (std::logic_error &e) { |
|---|
| 110 | BOOST_TEST(e.what() == ""); |
|---|
| 111 | } |
|---|
| 112 | } |
|---|
| 113 | }; |
|---|
| 114 | |
|---|
| 115 | BOOST_FIXTURE_TEST_SUITE(rw_csv_test, Fixture); |
|---|
| 116 | |
|---|
| 117 | BOOST_AUTO_TEST_CASE(one_seq_no_data) { |
|---|
| 118 | write(cseq("test_sequence")); |
|---|
| 119 | BOOST_CHECK_EQUAL(nlines(), 2); |
|---|
| 120 | BOOST_CHECK_EQUAL( |
|---|
| 121 | output(), |
|---|
| 122 | "name\n" |
|---|
| 123 | "test_sequence\n" |
|---|
| 124 | ); |
|---|
| 125 | } |
|---|
| 126 | |
|---|
| 127 | BOOST_AUTO_TEST_CASE(two_seq_no_data) { |
|---|
| 128 | write(cseq("test_sequence1")); |
|---|
| 129 | write(cseq("test_sequence2")); |
|---|
| 130 | BOOST_CHECK_EQUAL(nlines(), 3); |
|---|
| 131 | BOOST_CHECK_EQUAL( |
|---|
| 132 | output(), |
|---|
| 133 | "name\n" |
|---|
| 134 | "test_sequence1\n" |
|---|
| 135 | "test_sequence2\n"); |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | BOOST_AUTO_TEST_CASE(one_seq_one_string) { |
|---|
| 139 | cseq c("test_sequence"); |
|---|
| 140 | c.set_attr("col1", "Some test data"); |
|---|
| 141 | write(c); |
|---|
| 142 | BOOST_CHECK_EQUAL(nlines(), 2); |
|---|
| 143 | BOOST_CHECK_EQUAL( |
|---|
| 144 | output(), |
|---|
| 145 | "name,col1\n" |
|---|
| 146 | "test_sequence,Some test data\n" |
|---|
| 147 | ); |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | BOOST_AUTO_TEST_CASE(one_seq_one_int) { |
|---|
| 151 | cseq c("test_sequence"); |
|---|
| 152 | c.set_attr("col1", 123); |
|---|
| 153 | write(c); |
|---|
| 154 | BOOST_CHECK_EQUAL(nlines(), 2); |
|---|
| 155 | BOOST_CHECK_EQUAL( |
|---|
| 156 | output(), |
|---|
| 157 | "name,col1\n" |
|---|
| 158 | "test_sequence,123\n" |
|---|
| 159 | ); |
|---|
| 160 | } |
|---|
| 161 | |
|---|
| 162 | BOOST_AUTO_TEST_CASE(escape_seqname) { |
|---|
| 163 | cseq c("test_se,quence"); |
|---|
| 164 | write(c); |
|---|
| 165 | BOOST_CHECK_EQUAL( |
|---|
| 166 | output(), |
|---|
| 167 | "name\n" |
|---|
| 168 | "\"test_se,quence\"\n" |
|---|
| 169 | ); |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | BOOST_AUTO_TEST_CASE(escape_comma) { |
|---|
| 173 | cseq c("seq"); |
|---|
| 174 | c.set_attr("data", "d1,d2,d2"); |
|---|
| 175 | write(c); |
|---|
| 176 | BOOST_CHECK_EQUAL( |
|---|
| 177 | output(), |
|---|
| 178 | "name,data\n" |
|---|
| 179 | "seq,\"d1,d2,d2\"\n" |
|---|
| 180 | ); |
|---|
| 181 | } |
|---|
| 182 | |
|---|
| 183 | BOOST_AUTO_TEST_CASE(escape_quote) { |
|---|
| 184 | cseq c("seq1"); |
|---|
| 185 | c.set_attr("data", "a quote '\"'"); |
|---|
| 186 | write(c); |
|---|
| 187 | cseq d("seq2"); |
|---|
| 188 | d.set_attr("data", "more \"quotes\" '\"\"'"); |
|---|
| 189 | write(d); |
|---|
| 190 | BOOST_CHECK_EQUAL( |
|---|
| 191 | output(), |
|---|
| 192 | "name,data\n" |
|---|
| 193 | "seq1,\"a quote '\"\"'\"\n" |
|---|
| 194 | "seq2,\"more \"\"quotes\"\" '\"\"\"\"'\"\n" |
|---|
| 195 | ); |
|---|
| 196 | } |
|---|
| 197 | |
|---|
| 198 | BOOST_AUTO_TEST_CASE(escape_multilines) { |
|---|
| 199 | cseq c("seq"); |
|---|
| 200 | c.set_attr("data", "multiple\nlines"); |
|---|
| 201 | write(c); |
|---|
| 202 | BOOST_CHECK_EQUAL( |
|---|
| 203 | output(), |
|---|
| 204 | "name,data\n" |
|---|
| 205 | "seq,\"multiple\nlines\"\n" |
|---|
| 206 | ); |
|---|
| 207 | } |
|---|
| 208 | |
|---|
| 209 | |
|---|
| 210 | BOOST_AUTO_TEST_CASE(cannot_write) { |
|---|
| 211 | auto check_msg = |
|---|
| 212 | [](const std::runtime_error &e) -> bool { |
|---|
| 213 | return std::string(e.what()).rfind("Unable to open", 0) == 0; |
|---|
| 214 | }; |
|---|
| 215 | BOOST_CHECK_EXCEPTION( |
|---|
| 216 | rw_csv::writer("/proc/version", copy_relatives, fields), |
|---|
| 217 | std::runtime_error, |
|---|
| 218 | check_msg |
|---|
| 219 | ); |
|---|
| 220 | } |
|---|
| 221 | |
|---|
| 222 | |
|---|
| 223 | BOOST_AUTO_TEST_CASE(sep_tsv) { |
|---|
| 224 | set_ext("tsv"); |
|---|
| 225 | cseq c("test_sequence"); |
|---|
| 226 | c.set_attr("col1", "Some test data"); |
|---|
| 227 | write(c); |
|---|
| 228 | BOOST_CHECK_EQUAL(nlines(), 2); |
|---|
| 229 | BOOST_CHECK_EQUAL( |
|---|
| 230 | output(), |
|---|
| 231 | "name\tcol1\n" |
|---|
| 232 | "test_sequence\tSome test data\n" |
|---|
| 233 | ); |
|---|
| 234 | } |
|---|
| 235 | |
|---|
| 236 | |
|---|
| 237 | BOOST_AUTO_TEST_CASE(sep_tsv_override) { |
|---|
| 238 | set_ext("tsv"); |
|---|
| 239 | configure({"--csv-sep", ";;"}); |
|---|
| 240 | cseq c("test_sequence"); |
|---|
| 241 | c.set_attr("col1", "Some test data"); |
|---|
| 242 | write(c); |
|---|
| 243 | BOOST_CHECK_EQUAL(nlines(), 2); |
|---|
| 244 | BOOST_CHECK_EQUAL( |
|---|
| 245 | output(), |
|---|
| 246 | "name;;col1\n" |
|---|
| 247 | "test_sequence;;Some test data\n" |
|---|
| 248 | ); |
|---|
| 249 | } |
|---|
| 250 | |
|---|
| 251 | BOOST_AUTO_TEST_CASE(nullptr_seq) { |
|---|
| 252 | writer = new rw_csv::writer(*outfile, copy_relatives, fields); |
|---|
| 253 | tray t; |
|---|
| 254 | t.aligned_sequence = nullptr; |
|---|
| 255 | (*writer)(t); |
|---|
| 256 | cseq c("seq"); |
|---|
| 257 | write(c); |
|---|
| 258 | (*writer)(t); |
|---|
| 259 | BOOST_CHECK_EQUAL( |
|---|
| 260 | output(), |
|---|
| 261 | "name\nseq\n" |
|---|
| 262 | ); |
|---|
| 263 | } |
|---|
| 264 | |
|---|
| 265 | BOOST_AUTO_TEST_SUITE_END(); // rw_csv_test |
|---|
| 266 | |
|---|
| 267 | /* |
|---|
| 268 | Local Variables: |
|---|
| 269 | mode:c++ |
|---|
| 270 | c-file-style:"stroustrup" |
|---|
| 271 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) |
|---|
| 272 | indent-tabs-mode:nil |
|---|
| 273 | fill-column:99 |
|---|
| 274 | End: |
|---|
| 275 | */ |
|---|
| 276 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : |
|---|