// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include #include #include #include #include "../rugnux/RugnuxInputKind.h" namespace { const std::string MODEL_CIF = "data_test\n#\n_cell.length_a 50.0\nloop_\n_atom_site.group_PDB\n_atom_site.id\n" "ATOM 1\n"; const std::string SF_CIF = "data_r1abcsf\n_cell.length_a 50.0\nloop_\n_refln.index_h\n_refln.index_k\n" "_refln.index_l\n_refln.intensity_meas\n1 0 0 10.0\n"; const std::string PDB = "HEADER TEST\nREMARK 1 SYNTHETIC\nCRYST1 50.000 50.000 50.000 90.00 90.00 90.00 P 1\n" "ATOM 1 CA ALA A 1 1.000 2.000 3.000 1.00 10.00 C\nEND\n"; std::string Write(const std::string &name, const std::string &content) { std::ofstream(name, std::ios::binary) << content; return name; } std::string WriteGz(const std::string &name, const std::string &content) { gzFile f = gzopen(name.c_str(), "wb"); gzwrite(f, content.data(), static_cast(content.size())); gzclose(f); return name; } } TEST_CASE("RugnuxInputKind_Classify", "[rugnux_inputs]") { using K = RugnuxInputKind; CHECK(ClassifyRugnuxInput(Write("ik_model.cif", MODEL_CIF)) == K::Model); CHECK(ClassifyRugnuxInput(Write("ik_sf.cif", SF_CIF)) == K::Reflections); CHECK(ClassifyRugnuxInput(Write("ik_diffrn.cif", "data_x\nloop_\n_diffrn_refln.index_h\n1\n")) == K::Reflections); CHECK(ClassifyRugnuxInput(Write("ik_model.pdb", PDB)) == K::Model); CHECK(ClassifyRugnuxInput(WriteGz("ik_model.pdb.gz", PDB)) == K::Model); CHECK(ClassifyRugnuxInput(WriteGz("ik_sf.cif.gz", SF_CIF)) == K::Reflections); // the name says nothing: a model in a file called .mtz, reflections in one called .pdb CHECK(ClassifyRugnuxInput(Write("ik_model_named.mtz", MODEL_CIF)) == K::Model); CHECK(ClassifyRugnuxInput(Write("ik_mtz_named.pdb", std::string("MTZ \0\0\0\0", 8) + "binary")) == K::Reflections); CHECK(ClassifyRugnuxInput(Write("ik_image.h5", std::string("\x89HDF\r\n\x1a\n\0\0\0\0", 12))) == K::Images); CHECK(ClassifyRugnuxInput(Write("ik_image.cbf", "###CBF: VERSION 1.5\ndata_image\n_array_data.data\n")) == K::Images); CHECK(ClassifyRugnuxInput(Write("ik_image2.cbf", "data_image\n_array_data.data\n_atom_site.x\n")) == K::Images); CHECK(ClassifyRugnuxInput(Write("ik_image.img", "{\nHEADER_BYTES= 512;\nDIM=2;\n}")) == K::Images); CHECK(ClassifyRugnuxInput(Write("ik_binary", std::string("\0\1\2\3\4\5\6\7\0\0\0\0\0\0\0\0x", 17))) == K::Images); // A PDB file without an atom is not a model CHECK(ClassifyRugnuxInput(Write("ik_noatom.pdb", "HEADER TEST\nEND\n")) == K::Images); // Both coordinates and reflections: the user has to say CHECK(ClassifyRugnuxInput(Write("ik_both.cif", MODEL_CIF + "loop_\n_refln.index_h\n1\n")) == K::Ambiguous); for (const char *f: {"ik_model.cif", "ik_sf.cif", "ik_diffrn.cif", "ik_model.pdb", "ik_model.pdb.gz", "ik_sf.cif.gz", "ik_model_named.mtz", "ik_mtz_named.pdb", "ik_image.h5", "ik_image.cbf", "ik_image2.cbf", "ik_image.img", "ik_binary", "ik_noatom.pdb", "ik_both.cif"}) std::filesystem::remove(f); } TEST_CASE("RugnuxInputKind_SplitAnyOrder", "[rugnux_inputs]") { const std::string img = Write("ik_s_image.h5", std::string("\x89HDF\r\n\x1a\n\0\0\0\0", 12)); const std::string model = Write("ik_s_model.pdb", PDB); const std::string sf = Write("ik_s_sf.cif", SF_CIF); for (const auto &order: std::vector>{{img, model, sf}, {model, sf, img}, {sf, img, model}}) { const RugnuxPositionalInputs s = SplitRugnuxInputs(order); CHECK(s.images == std::vector{img}); CHECK(s.model == model); CHECK(s.reflections == sf); } // image files keep their order; a path that is no file (yet) is left to the image readers const RugnuxPositionalInputs s = SplitRugnuxInputs({"later_master.h5", model, img}); CHECK(s.images == std::vector{"later_master.h5", img}); const std::string model2 = Write("ik_s_model2.cif", MODEL_CIF); CHECK_THROWS(SplitRugnuxInputs({img, model, model2})); CHECK_THROWS(SplitRugnuxInputs({sf, img, sf})); const std::string both = Write("ik_s_both.cif", MODEL_CIF + "loop_\n_refln.index_h\n1\n"); CHECK_THROWS(SplitRugnuxInputs({img, both})); for (const auto &f: {img, model, sf, model2, both}) std::filesystem::remove(f); }