[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master fc09a91 03/22: Add unit tests for MD5-related
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master fc09a91 03/22: Add unit tests for MD5-related functionality |
Date: |
Sat, 28 Mar 2020 18:23:35 -0400 (EDT) |
branch: master
commit fc09a919a9b1c1486aea0c21637d41b1904da94c
Author: Ilya Sinitsyn <address@hidden>
Commit: Gregory W. Chicares <address@hidden>
Add unit tests for MD5-related functionality
Add a new test for the recently added functions for reading MD5
checksum files and calculating MD5 checksums.
---
Makefile.am | 10 ++
md5sum_test.cpp | 332 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
objects.make | 8 ++
3 files changed, 350 insertions(+)
diff --git a/Makefile.am b/Makefile.am
index 5620892..513c3dd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -121,6 +121,7 @@ TESTS = \
test_materially_equal \
test_math_functions \
test_mc_enum \
+ test_md5sum \
test_miscellany \
test_mortality_rates \
test_name_value_pairs \
@@ -938,6 +939,15 @@ test_mc_enum_CXXFLAGS = $(AM_CXXFLAGS)
test_mc_enum_LDADD = \
$(BOOST_LIBS)
+test_md5sum_SOURCES = \
+ $(common_test_objects) \
+ md5.cpp \
+ md5sum.cpp \
+ md5sum_test.cpp
+test_md5sum_CXXFLAGS = $(AM_CXXFLAGS)
+test_md5sum_LDADD = \
+ $(BOOST_LIBS)
+
test_miscellany_SOURCES = \
$(common_test_objects) \
miscellany.cpp \
diff --git a/md5sum_test.cpp b/md5sum_test.cpp
new file mode 100644
index 0000000..d578c12
--- /dev/null
+++ b/md5sum_test.cpp
@@ -0,0 +1,332 @@
+// MD5 sum--unit test.
+//
+// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2013, 2014, 2015, 2016, 2017, 2018, 2019 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program 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 this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+#include "pchfile.hpp"
+
+#include "assert_lmi.hpp"
+#include "contains.hpp"
+#include "md5sum.hpp"
+#include "miscellany.hpp"
+#include "system_command.hpp"
+#include "test_tools.hpp"
+
+#include <boost/filesystem/convenience.hpp> // basename()
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
+#include <cstdio>
+#include <cstring> // memcpy(), strlen()
+#include <fstream>
+#include <string>
+#include <vector>
+
+namespace
+{
+char const* test_filename = "md5_file";
+
+// Use the windows line ending format to test the text mode too.
+std::string const test_text =
+ "The couple bought a lot of vegetables and paid with a cheque. They\r\n"
+ "did some sightseeing, but it was too hot outside. In a park they met\r\n"
+ "a colleague and had a dinner romantically. After the meal they\r\n"
+ "decided to visit the local zoo. A lot of people saw a leopard at the\r\n"
+ "zoo. Near the cage they met the colonel, a well known man doing\r\n"
+ "business. He looked a little bit strange, maybe his ancestors were\r\n"
+ "apache or shoshone indians. They may have travelled from coast to\r\n"
+ "coast and saw interesting places. In the evening every building\r\n"
+ "was lit."
+ ;
+
+char const* test_bin_checksum = "40e541710871106ebc596595da341dcb";
+
+#if defined LMI_MSW
+char const* test_text_checksum = "e9f0fbd7a758d253ecd48ccded29234c";
+#else
+// Under Linux text and binary modes are the same.
+char const* test_text_checksum = test_bin_checksum;
+#endif // defined LMI_MSW
+
+char const* md5sums_filename = "md5_sums";
+
+// TODO: Ignore asterisk character in strings while processing a code with
+// `test_coding_rules` utility to not generate "should fuse '*' with type"
+// warning.
+// Use the '\x2a' esqape sequence to workaround the issue mentioned above.
+std::string const md5sums_text =
+ "00112233445566778899aabbccddeeff test.txt\n"
+ "ffeeddccbbaa99887766554433221100 \x2atest.bin\n"
+ ;
+
+}
+
+std::ostream& operator<<(std::ostream& os, std::vector<md5sum_for_file> const&
v)
+{
+ for(auto const& s : v)
+ {
+ char delimiter;
+ switch (s.file_mode)
+ {
+ case md5_file_mode::binary:
+ delimiter = '*';
+ break;
+ case md5_file_mode::text:
+ delimiter = ' ';
+ break;
+ default:
+ throw std::runtime_error("Unrecognized file mode value");
+ }
+ os << s.md5sum << ' ' << delimiter << "'" << s.filename.string() <<
"'\n";
+ }
+ return os;
+}
+
+bool operator==(md5sum_for_file const& l, md5sum_for_file const& r)
+{
+ return
+ l.filename == r.filename
+ && l.md5sum == r.md5sum
+ && l.file_mode == r.file_mode
+ ;
+}
+
+/// MD5 sum--unit test.
+///
+/// Public members are declared in invocation order.
+
+class MD5SumTest
+{
+ public:
+ MD5SumTest();
+ ~MD5SumTest();
+
+ void TestMD5Calculation() const;
+ void TestMD5Reading() const;
+ void TestMD5ToHexString() const;
+
+ private:
+ void RemoveTestFilesIfNecessary(char const* file, int line) const;
+ void WriteAndCheckFile
+ (char const* filename
+ ,std::string const& text
+ ,char const* file
+ ,int line
+ ) const;
+
+ void InitializeTestFile() const;
+ void InitializeMD5SumsFile() const;
+};
+
+/// Before writing any test file, remove any old copy that may be left
+/// over from a previous run that failed to complete, because old
+/// copies can cause spurious error reports.
+
+MD5SumTest::MD5SumTest()
+{
+ RemoveTestFilesIfNecessary(__FILE__, __LINE__);
+
+ InitializeTestFile();
+ InitializeMD5SumsFile();
+}
+
+MD5SumTest::~MD5SumTest()
+{
+ RemoveTestFilesIfNecessary(__FILE__, __LINE__);
+}
+
+/// Test md5_read_checksum_stream and md5_read_checksum_file
+/// functions.
+
+void MD5SumTest::TestMD5Calculation() const
+{
+ // Test md5_calculate_stream_checksum function.
+ std::ifstream is_text{test_filename, std::ios_base::in};
+ BOOST_TEST_EQUAL
+ (test_text_checksum
+ ,md5_calculate_stream_checksum(is_text, test_filename)
+ );
+
+ std::ifstream is_bin{test_filename, ios_in_binary()};
+ BOOST_TEST_EQUAL
+ (test_bin_checksum
+ ,md5_calculate_stream_checksum(is_bin, test_filename)
+ );
+
+ std::istringstream is_fail{test_text, std::ios_base::in};
+ is_fail.setstate(std::ios_base::failbit);
+ BOOST_TEST_THROW
+ (md5_calculate_stream_checksum(is_fail, test_filename)
+ ,std::runtime_error
+ ,"'md5_file': failed to read data while computing md5sum"
+ );
+
+ // Test md5_calculate_file_checksum function.
+ BOOST_TEST_EQUAL
+ (test_text_checksum
+ ,md5_calculate_file_checksum(test_filename, md5_file_mode::text)
+ );
+
+ BOOST_TEST_EQUAL
+ (test_bin_checksum
+ ,md5_calculate_file_checksum(test_filename, md5_file_mode::binary)
+ );
+
+ BOOST_TEST_EQUAL
+ (md5_calculate_file_checksum(md5sums_filename, md5_file_mode::text)
+ ,md5_calculate_file_checksum(md5sums_filename, md5_file_mode::binary)
+ );
+
+ BOOST_TEST_THROW
+ (md5_calculate_file_checksum("_ghost_")
+ ,std::runtime_error
+ ,"'_ghost_': no such file or directory"
+ );
+}
+
+/// Test md5_calculate_stream_checksum and md5_calculate_file_checksum
+/// functions.
+
+void MD5SumTest::TestMD5Reading() const
+{
+ std::vector<md5sum_for_file> md5sums
+ {{"test.txt", "00112233445566778899aabbccddeeff", md5_file_mode::text}
+ ,{"test.bin", "ffeeddccbbaa99887766554433221100",
md5_file_mode::binary}
+ };
+
+ // Test md5_read_checksum_stream function.
+ std::istringstream is_sums{md5sums_text};
+ BOOST_TEST_EQUAL
+ (md5sums
+ ,md5_read_checksum_stream(is_sums, md5sums_filename)
+ );
+
+ std::istringstream is_throw1{"00112233445566778899aabbccddeeff \n"};
+ BOOST_TEST_THROW
+ (md5_read_checksum_stream(is_throw1, "test1")
+ ,std::runtime_error
+ ,"'test1': line too short at line 1"
+ );
+
+ std::istringstream is_throw2{"00112233445566778899aabbccddeeff_test\n"};
+ BOOST_TEST_THROW
+ (md5_read_checksum_stream(is_throw2, "test2")
+ ,std::runtime_error
+ ,"'test2': incorrect checksum line format at line 1"
+ );
+
+ std::istringstream is_throw3{"00112233445566778899aabbccddeeff test\n"};
+ BOOST_TEST_THROW
+ (md5_read_checksum_stream(is_throw3, "test3")
+ ,std::runtime_error
+ ,"'test3': incorrect checksum line format at line 1"
+ );
+
+ std::istringstream is_throw4{"00112233445566778899aabbccddee test\n"};
+ BOOST_TEST_THROW
+ (md5_read_checksum_stream(is_throw4, "test4")
+ ,std::runtime_error
+ ,"'test4': incorrect MD5 sum format at line 1"
+ );
+
+ // Test md5_read_checksum_file function.
+ BOOST_TEST_EQUAL(md5sums, md5_read_checksum_file(md5sums_filename));
+
+ BOOST_TEST_THROW
+ (md5_read_checksum_file("_ghost_")
+ ,std::runtime_error
+ ,"'_ghost_': no such file or directory"
+ );
+}
+
+/// Test md5_hex_string function.
+
+void MD5SumTest::TestMD5ToHexString() const
+{
+ std::vector<unsigned char> v
+ {0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69, 0x78
+ ,0x87, 0x96, 0xa5, 0xb4, 0xc3, 0xd2, 0xe1, 0xf0
+ };
+ BOOST_TEST_EQUAL("0f1e2d3c4b5a69788796a5b4c3d2e1f0", md5_hex_string(v));
+}
+
+void MD5SumTest::RemoveTestFilesIfNecessary(char const* file, int line) const
+{
+ auto const RemoveIfNecessary = [file, line](char const* filename)
+ {
+ if(fs::exists(filename))
+ {
+ INVOKE_BOOST_TEST(std::remove(filename) == 0, file, line);
+ }
+ };
+
+ RemoveIfNecessary(test_filename);
+ RemoveIfNecessary(md5sums_filename);
+}
+
+/// Write the text to the file.
+///
+/// Read the file back after the writing and check the content.
+
+void MD5SumTest::WriteAndCheckFile
+ (char const* filename
+ ,std::string const& text
+ ,char const* file
+ ,int line
+ ) const
+{
+ std::ofstream os{filename, ios_out_trunc_binary()};
+ INVOKE_BOOST_TEST(os.good(), file, line);
+ os << text;
+ os.close();
+
+ // Read the file back.
+ std::ifstream is{filename, ios_in_binary()};
+ INVOKE_BOOST_TEST(is.good(), file, line);
+ std::ostringstream oss;
+ oss << is.rdbuf();
+ is.close();
+
+ INVOKE_BOOST_TEST_EQUAL(text, oss.str(), file, line);
+}
+
+/// Write a text file for testing.
+
+void MD5SumTest::InitializeTestFile() const
+{
+ WriteAndCheckFile(test_filename, test_text, __FILE__, __LINE__);
+}
+
+/// Write the file with the file name and the md5 sum of the test file.
+
+void MD5SumTest::InitializeMD5SumsFile() const
+{
+ WriteAndCheckFile(md5sums_filename, md5sums_text, __FILE__, __LINE__);
+}
+
+int test_main(int, char*[])
+{
+ MD5SumTest tester;
+ tester.TestMD5Calculation();
+ tester.TestMD5Reading();
+ tester.TestMD5ToHexString();
+
+ return EXIT_SUCCESS;
+}
diff --git a/objects.make b/objects.make
index 8b9dc0e..8e86a5e 100644
--- a/objects.make
+++ b/objects.make
@@ -444,6 +444,7 @@ unit_test_targets := \
materially_equal_test \
math_functions_test \
mc_enum_test \
+ md5sum_test \
miscellany_test \
mortality_rates_test \
name_value_pairs_test \
@@ -823,6 +824,13 @@ mc_enum_test$(EXEEXT): \
null_stream.o \
path_utility.o \
+md5sum_test$(EXEEXT): \
+ $(boost_filesystem_objects) \
+ $(common_test_objects) \
+ md5.o \
+ md5sum.o \
+ md5sum_test.o \
+
miscellany_test$(EXEEXT): \
$(common_test_objects) \
miscellany.o \
- [lmi-commits] [lmi] master f340f72 06/22: Explicitly qualify std::size_t, (continued)
- [lmi-commits] [lmi] master f340f72 06/22: Explicitly qualify std::size_t, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 2696d31 04/22: Update copyright notices, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 2b4947a 08/22: Write inequality comparisons in number-line order, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 063c376 10/22: Generally avoid "`" where "'" is at least as good, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 0622c32 07/22: Regularize whitespace, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master c029dd3 12/22: Improve documentation, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 4cafdca 02/22: Add lmi_md5sum utility implementing subset of standard md5sum, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master d82ac15 13/22: Split a long line, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 28956d7 14/22: Temporarily allow an "MD5 !!" marker, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 925f946 05/22: Include headers iff appropriate, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master fc09a91 03/22: Add unit tests for MD5-related functionality,
Greg Chicares <=
- [lmi-commits] [lmi] master 225cf10 09/22: Avoid a warning by a different means, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 2db19f5 11/22: Remove unnecessary shared-object attributes, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 28f8ffc 15/22: Explicitly qualify std::cout, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master f14ad11 01/22: Implement MD5 checksum files reading in lmi code, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master ec4fe67 18/22: Realphabetize a list, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 8d3e03a 20/22: Expunge a disused makefile variable, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 72ee60f 17/22: Improve instructions, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 9ae6e81 19/22: Reformat and lightly revise some documentation, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 9c510ad 16/22: Measure elapsed time for MD5 data-file validation, Greg Chicares, 2020/03/28
- [lmi-commits] [lmi] master 6645aa7 21/22: Eradicate 'winebindir', Greg Chicares, 2020/03/28