From dd34301b138598b3ee66d3677cfa0a6a0034242d Mon Sep 17 00:00:00 2001 From: Ben Webb Date: Thu, 15 Feb 2024 21:53:22 -0800 Subject: [PATCH] rmf_cat: check mismatched structure/static frame Check all the input files passed to rmf_cat to make sure that they have the same structure and static frame, and exit with an error if they don't. Add a --force option to allow the user to override this check if desired. Closes #128. --- bin/rmf_cat.cpp | 25 ++++++++++++++++++- doc/Executables.md | 1 + test/test_rmf_cat.py | 59 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 test/test_rmf_cat.py diff --git a/bin/rmf_cat.cpp b/bin/rmf_cat.cpp index 9ec94438..553f88f6 100644 --- a/bin/rmf_cat.cpp +++ b/bin/rmf_cat.cpp @@ -21,19 +21,42 @@ std::string output; } int main(int argc, char** argv) { try { + options.add_options()("force,f", + "Combine files even if they have different " + "structure or static frames."); positional_options.add_options()( "input-files,i", boost::program_options::value >(&inputs), "input rmf file"); positional_names.emplace_back("input_1.rmf input_2.rmf ... output.rmf"); positional_options_description.add("input-files", -1); - process_options(argc, argv); + boost::program_options::variables_map vm(process_options(argc, argv)); + if (inputs.size() < 3) { print_help_and_exit(argv); } output = inputs.back(); inputs.pop_back(); + bool force = vm.count("force"); + if (!force && inputs.size() > 1) { + RMF::FileConstHandle rh1 = RMF::open_rmf_file_read_only(inputs[0]); + for (unsigned int i = 1; i < inputs.size(); ++i) { + RMF::FileConstHandle rh2 = RMF::open_rmf_file_read_only(inputs[i]); + if (!RMF::get_equal_structure(rh1, rh2, true)) { + std::cerr << inputs[0] << " and " << inputs[i] + << " have different structure, cannot concatenate " + << "without --force" << std::endl; + exit(1); + } + if (!RMF::get_equal_static_values(rh1, rh2)) { + std::cerr << inputs[0] << " and " << inputs[i] + << " have different static frames, cannot concatenate " + << "without --force" << std::endl; + exit(1); + } + } + } RMF::FileHandle orh = RMF::create_rmf_file(output); orh.set_producer("rmf_cat"); for (unsigned int i = 0; i < inputs.size(); ++i) { diff --git a/doc/Executables.md b/doc/Executables.md index 5b1bb065..5924c29a 100644 --- a/doc/Executables.md +++ b/doc/Executables.md @@ -52,6 +52,7 @@ and how much they are used. Combine two or more rmf files. Usage: ./bin/rmf_cat input_1.rmf input_2.rmf ... output.rmf + -f [ --force ] Combine files even if they have different structure or static frame. -h [ --help ] Get help on command line arguments. -v [ --verbose ] Produce more output. --hdf5-errors Show hdf5 errors. diff --git a/test/test_rmf_cat.py b/test/test_rmf_cat.py new file mode 100644 index 00000000..6acfea27 --- /dev/null +++ b/test/test_rmf_cat.py @@ -0,0 +1,59 @@ +import unittest +import os +import RMF +import subprocess + + +class Tests(unittest.TestCase): + + def test_help(self): + """Test rmf_cat --help""" + p = subprocess.Popen(['rmf_cat', '--help'], stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True) + out, err = p.communicate() + self.assertEqual(out, "") + self.assertIn("Combine two or more rmf files", err) + self.assertEqual(p.returncode, 1) + + def test_version(self): + """Test rmf_cat --version""" + p = subprocess.Popen(['rmf_cat', '--version'], stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True) + out, err = p.communicate() + self.assertEqual(err, "") + self.assertIn("RMF version", out) + self.assertEqual(p.returncode, 0) + + def test_cat_mismatch(self): + """Test rmf_cat of mismatched files""" + p = subprocess.Popen( + ['rmf_cat', RMF._get_test_input_file_path("simple.rmf"), + RMF._get_test_input_file_path("rep_and_geom.rmf"), + 'test_cat_mismatch.rmf'], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, universal_newlines=True) + out, err = p.communicate() + self.assertIn("have different structure", err) + self.assertEqual(p.returncode, 1) + + def test_cat_ok(self): + """Test rmf_cat of similar files""" + p = subprocess.Popen( + ['rmf_cat', RMF._get_test_input_file_path("simple.rmf"), + RMF._get_test_input_file_path("simple-new.rmf"), + 'test_cat_ok.rmf'], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, universal_newlines=True) + out, err = p.communicate() + self.assertEqual(out, "") + self.assertEqual(err, "") + self.assertEqual(p.returncode, 0) + os.unlink('test_cat_ok.rmf') + + +if __name__ == '__main__': + unittest.main()