From 16e44719e2ad1d22aedd5eb1c88422cf6fa35f55 Mon Sep 17 00:00:00 2001 From: "Mark A. Tsuchida" Date: Thu, 14 Dec 2023 16:04:16 -0600 Subject: [PATCH 1/4] Remove MMDevice/MMCore unit tests from Automake We do not run these tests from CI using Automake currently, and there is not much of an advantage in doing so because we now have them run using the experimental Meson build for MMDevice and MMCore. So remove from the Automake build so that these tests can be evolved (including switching the testing framework away from GoogleTest) without having to update the Automake build. For the couple of device adapters that have unit tests, those can still be run from Automake. --- MMCore/Makefile.am | 6 ------ MMCore/unittest/Makefile.am | 9 --------- MMDevice/Makefile.am | 2 -- MMDevice/unittest/Makefile.am | 7 ------- 4 files changed, 24 deletions(-) delete mode 100644 MMCore/unittest/Makefile.am delete mode 100644 MMDevice/unittest/Makefile.am diff --git a/MMCore/Makefile.am b/MMCore/Makefile.am index d56ad5273..013860a8a 100644 --- a/MMCore/Makefile.am +++ b/MMCore/Makefile.am @@ -99,10 +99,4 @@ libMMCore_la_SOURCES = \ ThreadPool.cpp \ ThreadPool.h -if BUILD_CPP_TESTS -UNITTESTS = unittest -endif - -SUBDIRS = . $(UNITTESTS) - EXTRA_DIST = license.txt diff --git a/MMCore/unittest/Makefile.am b/MMCore/unittest/Makefile.am deleted file mode 100644 index 26eec6399..000000000 --- a/MMCore/unittest/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -check_PROGRAMS = \ - APIError-Tests \ - CoreSanity-Tests \ - LoggingSplitEntryIntoLines-Tests \ - Logger-Tests -AM_DEFAULT_SOURCE_EXT = .cpp -AM_CPPFLAGS = $(GMOCK_CPPFLAGS) -I.. -LDADD = ../../../testing/libgmock.la ../libMMCore.la -TESTS = $(check_PROGRAMS) diff --git a/MMDevice/Makefile.am b/MMDevice/Makefile.am index 33444b2e0..19dd6dba4 100644 --- a/MMDevice/Makefile.am +++ b/MMDevice/Makefile.am @@ -36,5 +36,3 @@ install: install-am uninstall: uninstall-am rm -f $(DESTDIR)${libdir}/libMMDevice.a endif - -SUBDIRS = . unittest diff --git a/MMDevice/unittest/Makefile.am b/MMDevice/unittest/Makefile.am deleted file mode 100644 index e86d01c07..000000000 --- a/MMDevice/unittest/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ -check_PROGRAMS = \ - FloatPropertyTruncation-Tests \ - MMTime-Tests -AM_DEFAULT_SOURCE_EXT = .cpp -AM_CPPFLAGS = $(GMOCK_CPPFLAGS) -I.. -LDADD = ../../../testing/libgmock.la ../libMMDevice.la -TESTS = $(check_PROGRAMS) From 51adfab0a80e4957ed92e4b0145ddad70d5028e7 Mon Sep 17 00:00:00 2001 From: "Mark A. Tsuchida" Date: Thu, 14 Dec 2023 16:17:30 -0600 Subject: [PATCH 2/4] MMDevice/MMCore: Use single executable for tests And use GoogleTest's default main() implementation. --- MMCore/unittest/APIError-Tests.cpp | 6 --- MMCore/unittest/CoreSanity-Tests.cpp | 8 +-- MMCore/unittest/Logger-Tests.cpp | 9 +--- .../LoggingSplitEntryIntoLines-Tests.cpp | 9 +--- MMCore/unittest/meson.build | 49 ++++--------------- .../FloatPropertyTruncation-Tests.cpp | 9 +--- MMDevice/unittest/MMTime-Tests.cpp | 8 +-- MMDevice/unittest/meson.build | 31 +++++------- 8 files changed, 26 insertions(+), 103 deletions(-) diff --git a/MMCore/unittest/APIError-Tests.cpp b/MMCore/unittest/APIError-Tests.cpp index 94b0557e1..66ab0df2e 100644 --- a/MMCore/unittest/APIError-Tests.cpp +++ b/MMCore/unittest/APIError-Tests.cpp @@ -84,10 +84,4 @@ TEST(APIErrorTests, DetectDeviceWithInvalidDevice) EXPECT_EQ(MM::Unimplemented, c.detectDevice("")); EXPECT_EQ(MM::Unimplemented, c.detectDevice("Blah")); EXPECT_EQ(MM::Unimplemented, c.detectDevice("Core")); -} - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); } \ No newline at end of file diff --git a/MMCore/unittest/CoreSanity-Tests.cpp b/MMCore/unittest/CoreSanity-Tests.cpp index 2cbd9ad2b..4abb5f5a2 100644 --- a/MMCore/unittest/CoreSanity-Tests.cpp +++ b/MMCore/unittest/CoreSanity-Tests.cpp @@ -22,10 +22,4 @@ TEST(CoreSanityTests, CreateAndReset) { CMMCore c; c.reset(); -} - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} +} \ No newline at end of file diff --git a/MMCore/unittest/Logger-Tests.cpp b/MMCore/unittest/Logger-Tests.cpp index 3eb892853..7da24b8c9 100644 --- a/MMCore/unittest/Logger-Tests.cpp +++ b/MMCore/unittest/Logger-Tests.cpp @@ -117,11 +117,4 @@ TEST(LoggerTests, AsyncAndThreaded) } for (unsigned i = 0; i < threads.size(); ++i) threads[i]->join(); -} - - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} +} \ No newline at end of file diff --git a/MMCore/unittest/LoggingSplitEntryIntoLines-Tests.cpp b/MMCore/unittest/LoggingSplitEntryIntoLines-Tests.cpp index 2ca1a0cb0..917bbe3a8 100644 --- a/MMCore/unittest/LoggingSplitEntryIntoLines-Tests.cpp +++ b/MMCore/unittest/LoggingSplitEntryIntoLines-Tests.cpp @@ -219,11 +219,4 @@ INSTANTIATE_TEST_SUITE_P(TwoSoftSplitCase, ::testing::Values( std::string(2 * MaxLogLineLen + 1, 'x'), std::string(3 * MaxLogLineLen - 1, 'x'), - std::string(3 * MaxLogLineLen, 'x'))); - - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} + std::string(3 * MaxLogLineLen, 'x'))); \ No newline at end of file diff --git a/MMCore/unittest/meson.build b/MMCore/unittest/meson.build index 05395a28c..92ca4b566 100644 --- a/MMCore/unittest/meson.build +++ b/MMCore/unittest/meson.build @@ -2,28 +2,18 @@ # of the supported build system for Micro-Manager or mmCoreAndDevices. gtest_proj = subproject('gtest') -gtest_dep = gtest_proj.get_variable('gtest_dep') +gtest_dep = gtest_proj.get_variable('gtest_main_dep') -# TODO: Use a single executable for all tests -- but that requires modifying -# the sources (to remove main()), so needs to wait until we remove these tests -# from the Automake build. - -mmcore_apierror_test_exe = executable( - 'MMCoreAPIErrorTest', - sources: 'APIError-Tests.cpp', - include_directories: mmcore_include_dir, - link_with: mmcore_lib, - dependencies: [ - mmdevice_dep, - gtest_dep, - ], +mmcore_test_sources = files( + 'APIError-Tests.cpp', + 'CoreSanity-Tests.cpp', + 'Logger-Tests.cpp', + 'LoggingSplitEntryIntoLines-Tests.cpp', ) -test('MMCore APIError test', mmcore_apierror_test_exe) - -mmcore_logger_test_exe = executable( - 'MMCoreLoggerTest', - sources: 'Logger-Tests.cpp', +mmcore_test_exe = executable( + 'MMCoreTests', + sources: mmcore_test_sources, include_directories: mmcore_include_dir, link_with: mmcore_lib, dependencies: [ @@ -35,23 +25,4 @@ mmcore_logger_test_exe = executable( ], ) -test('MMCore Logger test', mmcore_logger_test_exe) - -mmcore_loggingsplitentryintolines_test_exe = executable( - 'MMCoreLoggingSplitEntryIntoLinesTest', - sources: 'LoggingSplitEntryIntoLines-Tests.cpp', - include_directories: mmcore_include_dir, - link_with: mmcore_lib, - dependencies: [ - mmdevice_dep, - gtest_dep, - ], - cpp_args: [ - '-D_CRT_SECURE_NO_WARNINGS', # TODO Eliminate the need - ], -) - -test( - 'MMCore LoggingSplitEntryIntoLines test', - mmcore_loggingsplitentryintolines_test_exe -) +test('MMCore tests', mmcore_test_exe) \ No newline at end of file diff --git a/MMDevice/unittest/FloatPropertyTruncation-Tests.cpp b/MMDevice/unittest/FloatPropertyTruncation-Tests.cpp index f6ee76d22..abcfccb3c 100644 --- a/MMDevice/unittest/FloatPropertyTruncation-Tests.cpp +++ b/MMDevice/unittest/FloatPropertyTruncation-Tests.cpp @@ -65,11 +65,4 @@ TEST(FloatPropertyTruncationTests, UpperLimitIsTruncatedDown) ASSERT_DOUBLE_EQ(-0.0001, fp.GetUpperLimit()); ASSERT_TRUE(fp.SetLimits(-1000.0, -0.00011)); ASSERT_DOUBLE_EQ(-0.0002, fp.GetUpperLimit()); -} - - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} +} \ No newline at end of file diff --git a/MMDevice/unittest/MMTime-Tests.cpp b/MMDevice/unittest/MMTime-Tests.cpp index e31fc522a..174b5d6c2 100644 --- a/MMDevice/unittest/MMTime-Tests.cpp +++ b/MMDevice/unittest/MMTime-Tests.cpp @@ -66,10 +66,4 @@ TEST(MMTimeTests, ToNumbers) { ASSERT_DOUBLE_EQ(1.0, MMTime(1.0).getUsec()); ASSERT_DOUBLE_EQ(1.0, MMTime(1000.0).getMsec()); -} - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} +} \ No newline at end of file diff --git a/MMDevice/unittest/meson.build b/MMDevice/unittest/meson.build index 0b9296ac2..603a26673 100644 --- a/MMDevice/unittest/meson.build +++ b/MMDevice/unittest/meson.build @@ -2,31 +2,22 @@ # of the supported build system for Micro-Manager or mmCoreAndDevices. gtest_proj = subproject('gtest') -gtest_dep = gtest_proj.get_variable('gtest_dep') +gtest_dep = gtest_proj.get_variable('gtest_main_dep') -# TODO: Use a single executable for all tests -- but that requires modifying -# the sources (to remove main()), so needs to wait until we remove these tests -# from the Automake build. - -mmdevice_floatpropertytruncation_test_exe = executable( - 'MMDeviceFloatPropertyTruncationTest', - sources: 'FloatPropertyTruncation-Tests.cpp', - include_directories: mmdevice_include_dir, - link_with: mmdevice_lib, - dependencies: gtest_dep, +mmdevice_test_sources = files( + 'FloatPropertyTruncation-Tests.cpp', + 'MMTime-Tests.cpp', ) -test( - 'MMDevice FloatPropertyTruncation test', - mmdevice_floatpropertytruncation_test_exe, -) - -mmdevice_mmtime_test_exe = executable( - 'MMDeviceMMTimeTest', - sources: 'MMTime-Tests.cpp', +mmdevice_test_exe = executable( + 'MMDeviceTests', + sources: mmdevice_test_sources, include_directories: mmdevice_include_dir, link_with: mmdevice_lib, dependencies: gtest_dep, ) -test('MMDevice MMTime test', mmdevice_mmtime_test_exe) +test( + 'MMDevice unit tests', + mmdevice_test_exe, +) \ No newline at end of file From 9d625c384b4da6dfe77b800fb0a4ccc610c0cd34 Mon Sep 17 00:00:00 2001 From: "Mark A. Tsuchida" Date: Mon, 18 Dec 2023 14:58:32 -0600 Subject: [PATCH 3/4] MMDevice: Switch from GoogleTest to Catch2 --- MMDevice/subprojects/.gitignore | 2 +- MMDevice/subprojects/catch2.wrap | 11 +++ MMDevice/subprojects/gtest.wrap | 16 ---- .../FloatPropertyTruncation-Tests.cpp | 91 +++++++++--------- MMDevice/unittest/MMTime-Tests.cpp | 92 +++++++++---------- MMDevice/unittest/meson.build | 9 +- 6 files changed, 107 insertions(+), 114 deletions(-) create mode 100644 MMDevice/subprojects/catch2.wrap delete mode 100644 MMDevice/subprojects/gtest.wrap diff --git a/MMDevice/subprojects/.gitignore b/MMDevice/subprojects/.gitignore index 8b7ac1334..9a8e50c79 100644 --- a/MMDevice/subprojects/.gitignore +++ b/MMDevice/subprojects/.gitignore @@ -7,4 +7,4 @@ /*.wrap # Do not ignore wraps we provide -!/gtest.wrap \ No newline at end of file +!/catch2.wrap diff --git a/MMDevice/subprojects/catch2.wrap b/MMDevice/subprojects/catch2.wrap new file mode 100644 index 000000000..691d39c85 --- /dev/null +++ b/MMDevice/subprojects/catch2.wrap @@ -0,0 +1,11 @@ +[wrap-file] +directory = Catch2-3.4.0 +source_url = https://github.com/catchorg/Catch2/archive/v3.4.0.tar.gz +source_filename = Catch2-3.4.0.tar.gz +source_hash = 122928b814b75717316c71af69bd2b43387643ba076a6ec16e7882bfb2dfacbb +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/catch2_3.4.0-1/Catch2-3.4.0.tar.gz +wrapdb_version = 3.4.0-1 + +[provide] +catch2 = catch2_dep +catch2-with-main = catch2_with_main_dep diff --git a/MMDevice/subprojects/gtest.wrap b/MMDevice/subprojects/gtest.wrap deleted file mode 100644 index 8c067ff20..000000000 --- a/MMDevice/subprojects/gtest.wrap +++ /dev/null @@ -1,16 +0,0 @@ -[wrap-file] -directory = googletest-1.14.0 -source_url = https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz -source_filename = gtest-1.14.0.tar.gz -source_hash = 8ad598c73ad796e0d8280b082cebd82a630d73e73cd3c70057938a6501bba5d7 -patch_filename = gtest_1.14.0-1_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/gtest_1.14.0-1/get_patch -patch_hash = 2e693c7d3f9370a7aa6dac802bada0874d3198ad4cfdf75647b818f691182b50 -source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/gtest_1.14.0-1/gtest-1.14.0.tar.gz -wrapdb_version = 1.14.0-1 - -[provide] -gtest = gtest_dep -gtest_main = gtest_main_dep -gmock = gmock_dep -gmock_main = gmock_main_dep diff --git a/MMDevice/unittest/FloatPropertyTruncation-Tests.cpp b/MMDevice/unittest/FloatPropertyTruncation-Tests.cpp index abcfccb3c..9c041baec 100644 --- a/MMDevice/unittest/FloatPropertyTruncation-Tests.cpp +++ b/MMDevice/unittest/FloatPropertyTruncation-Tests.cpp @@ -1,68 +1,67 @@ -#include +#include #include "Property.h" -using namespace MM; +namespace MM { - -TEST(FloatPropertyTruncationTests, SetValueIsTruncatedTo4Digits) +TEST_CASE("Set value is truncated to 4 digits", "[FloatPropertyTruncation]") { FloatProperty fp("TestProp"); double v; - ASSERT_TRUE(fp.Set(0.00004)); - ASSERT_TRUE(fp.Get(v)); - ASSERT_DOUBLE_EQ(0.0, v); + CHECK(fp.Set(0.00004)); + CHECK(fp.Get(v)); + CHECK(v == 0.0); - ASSERT_TRUE(fp.Set(0.00005)); - ASSERT_TRUE(fp.Get(v)); - ASSERT_DOUBLE_EQ(0.0001, v); + CHECK(fp.Set(0.00005)); + CHECK(fp.Get(v)); + CHECK(v == 0.0001); - ASSERT_TRUE(fp.Set(-0.00004)); - ASSERT_TRUE(fp.Get(v)); - ASSERT_DOUBLE_EQ(0.0, v); + CHECK(fp.Set(-0.00004)); + CHECK(fp.Get(v)); + CHECK(v == 0.0); - ASSERT_TRUE(fp.Set(-0.00005)); - ASSERT_TRUE(fp.Get(v)); - ASSERT_DOUBLE_EQ(-0.0001, v); + CHECK(fp.Set(-0.00005)); + CHECK(fp.Get(v)); + CHECK(v == -0.0001); } - -TEST(FloatPropertyTruncationTests, LowerLimitIsTruncatedUp) +TEST_CASE("Lower limit is truncated up", "[FloatPropertyTruncation]") { FloatProperty fp("TestProp"); - ASSERT_TRUE(fp.SetLimits(0.0, 1000.0)); - ASSERT_DOUBLE_EQ(0.0, fp.GetLowerLimit()); - ASSERT_TRUE(fp.SetLimits(0.00001, 1000.0)); - ASSERT_DOUBLE_EQ(0.0001, fp.GetLowerLimit()); - ASSERT_TRUE(fp.SetLimits(0.00011, 1000.0)); - ASSERT_DOUBLE_EQ(0.0002, fp.GetLowerLimit()); - - ASSERT_TRUE(fp.SetLimits(-0.0, 1000.0)); - ASSERT_DOUBLE_EQ(0.0, fp.GetLowerLimit()); - ASSERT_TRUE(fp.SetLimits(-0.00001, 1000.0)); - ASSERT_DOUBLE_EQ(0.0, fp.GetLowerLimit()); - ASSERT_TRUE(fp.SetLimits(-0.00011, 1000.0)); - ASSERT_DOUBLE_EQ(-0.0001, fp.GetLowerLimit()); + CHECK(fp.SetLimits(0.0, 1000.0)); + CHECK(fp.GetLowerLimit() == 0.0); + CHECK(fp.SetLimits(0.00001, 1000.0)); + CHECK(fp.GetLowerLimit() == 0.0001); + CHECK(fp.SetLimits(0.00011, 1000.0)); + CHECK(fp.GetLowerLimit() == 0.0002); + + CHECK(fp.SetLimits(-0.0, 1000.0)); + CHECK(fp.GetLowerLimit() == 0.0); + CHECK(fp.SetLimits(-0.00001, 1000.0)); + CHECK(fp.GetLowerLimit() == 0.0); + CHECK(fp.SetLimits(-0.00011, 1000.0)); + CHECK(fp.GetLowerLimit() == -0.0001); } - -TEST(FloatPropertyTruncationTests, UpperLimitIsTruncatedDown) +TEST_CASE("Upper limit is truncated down", "[FloatPropertyTruncation]") { FloatProperty fp("TestProp"); - ASSERT_TRUE(fp.SetLimits(-1000.0, 0.0)); - ASSERT_DOUBLE_EQ(0.0, fp.GetUpperLimit()); - ASSERT_TRUE(fp.SetLimits(-1000.0, 0.00001)); - ASSERT_DOUBLE_EQ(0.0, fp.GetUpperLimit()); - ASSERT_TRUE(fp.SetLimits(-1000.0, 0.00011)); - ASSERT_DOUBLE_EQ(0.0001, fp.GetUpperLimit()); + CHECK(fp.SetLimits(-1000.0, 0.0)); + CHECK(fp.GetUpperLimit() == 0.0); + CHECK(fp.SetLimits(-1000.0, 0.00001)); + CHECK(fp.GetUpperLimit() == 0.0); + CHECK(fp.SetLimits(-1000.0, 0.00011)); + CHECK(fp.GetUpperLimit() == 0.0001); + + CHECK(fp.SetLimits(-1000.0, -0.0)); + CHECK(fp.GetUpperLimit() == 0.0); + CHECK(fp.SetLimits(-1000.0, -0.00001)); + CHECK(fp.GetUpperLimit() == -0.0001); + CHECK(fp.SetLimits(-1000.0, -0.00011)); + CHECK(fp.GetUpperLimit() == -0.0002); +} - ASSERT_TRUE(fp.SetLimits(-1000.0, -0.0)); - ASSERT_DOUBLE_EQ(0.0, fp.GetUpperLimit()); - ASSERT_TRUE(fp.SetLimits(-1000.0, -0.00001)); - ASSERT_DOUBLE_EQ(-0.0001, fp.GetUpperLimit()); - ASSERT_TRUE(fp.SetLimits(-1000.0, -0.00011)); - ASSERT_DOUBLE_EQ(-0.0002, fp.GetUpperLimit()); -} \ No newline at end of file +} // namespace MM \ No newline at end of file diff --git a/MMDevice/unittest/MMTime-Tests.cpp b/MMDevice/unittest/MMTime-Tests.cpp index 174b5d6c2..3dc3ad150 100644 --- a/MMDevice/unittest/MMTime-Tests.cpp +++ b/MMDevice/unittest/MMTime-Tests.cpp @@ -1,69 +1,65 @@ -#include +#include #include "MMDevice.h" -using namespace MM; +namespace MM { - -TEST(MMTimeTests, RoundTripNegativeValues) +TEST_CASE("MMTime round trip negative values", "[MMTime]") { - ASSERT_DOUBLE_EQ(0.0, MMTime(-0.4).getUsec()); - ASSERT_DOUBLE_EQ(-1.0, MMTime(-1.0).getUsec()); - ASSERT_DOUBLE_EQ(-1'000'000.0, MMTime(-1'000'000.0).getUsec()); + CHECK(MMTime(-0.4).getUsec() == 0.0); + CHECK(MMTime(-1.0).getUsec() == -1.0); + CHECK(MMTime(-1'000'000.0).getUsec() == -1'000'000.0); - ASSERT_DOUBLE_EQ(-1.0, MMTime(0, -1).getUsec()); - ASSERT_DOUBLE_EQ(-1'000'000.0, MMTime(-1, 0).getUsec()); - ASSERT_DOUBLE_EQ(-999'999.0, MMTime(-1, 1).getUsec()); - ASSERT_DOUBLE_EQ(-1'000'001.0, MMTime(-1, -1).getUsec()); + CHECK(MMTime(0, -1).getUsec() == -1.0); + CHECK(MMTime(-1, 0).getUsec() == -1'000'000.0); + CHECK(MMTime(-1, 1).getUsec() == -999'999.0); + CHECK(MMTime(-1, -1).getUsec() == -1'000'001.0); } - -TEST(MMTimeTests, ToString) +TEST_CASE("MMTime to string", "[MMTime]") { - using namespace std::literals::string_literals; - ASSERT_EQ("0.000000"s, MMTime{}.toString()); - ASSERT_EQ("0.000001"s, MMTime(0, 1).toString()); - ASSERT_EQ("-0.000001"s, MMTime(0, -1).toString()); - ASSERT_EQ("-0.000001"s, MMTime(-1, 999'999).toString()); - ASSERT_EQ("1.000000"s, MMTime(1, 0).toString()); - ASSERT_EQ("-1.000000"s, MMTime(-1, 0).toString()); - ASSERT_EQ("-1.000001"s, MMTime(-1, -1).toString()); - ASSERT_EQ("-0.999999"s, MMTime(-1, 1).toString()); + using namespace std::string_literals; + CHECK(MMTime{}.toString() == "0.000000"s); + CHECK(MMTime(0, 1).toString() == "0.000001"s); + CHECK(MMTime(0, -1).toString() == "-0.000001"s); + CHECK(MMTime(-1, 999'999).toString() == "-0.000001"s); + CHECK(MMTime(1, 0).toString() == "1.000000"s); + CHECK(MMTime(-1, 0).toString() == "-1.000000"s); + CHECK(MMTime(-1, -1).toString() == "-1.000001"s); + CHECK(MMTime(-1, 1).toString() == "-0.999999"s); } - -TEST(MMTimeTests, Arithmetic) +TEST_CASE("MMTime arithmetic", "[MMTime]") { - ASSERT_EQ(MMTime(5.0), MMTime(3.0) + MMTime(2.0)); - ASSERT_EQ(MMTime(1.0), MMTime(3.0) - MMTime(2.0)); - ASSERT_EQ(MMTime(-5.0), MMTime(-3.0) + MMTime(-2.0)); - ASSERT_EQ(MMTime(-1.0), MMTime(-3.0) - MMTime(-2.0)); + CHECK(MMTime(3.0) + MMTime(2.0) == MMTime(5.0)); + CHECK(MMTime(3.0) - MMTime(2.0) == MMTime(1.0)); + CHECK(MMTime(-3.0) + MMTime(-2.0) == MMTime(-5.0)); + CHECK(MMTime(-3.0) - MMTime(-2.0) == MMTime(-1.0)); } - -TEST(MMTimeTests, Comparison) +TEST_CASE("MMTime comparison", "[MMTime]") { - ASSERT_TRUE(MMTime(5.0) == MMTime(5.0)); - ASSERT_TRUE(MMTime(5.0) >= MMTime(5.0)); - ASSERT_TRUE(MMTime(5.0) <= MMTime(5.0)); - ASSERT_FALSE(MMTime(5.0) != MMTime(5.0)); - ASSERT_TRUE(MMTime(3.0) > MMTime(2.0)); - ASSERT_TRUE(MMTime(3.0) >= MMTime(2.0)); - ASSERT_TRUE(MMTime(2.0) < MMTime(3.0)); - ASSERT_TRUE(MMTime(2.0) <= MMTime(3.0)); + CHECK(MMTime(5.0) == MMTime(5.0)); + CHECK(MMTime(5.0) >= MMTime(5.0)); + CHECK(MMTime(5.0) <= MMTime(5.0)); + CHECK_FALSE(MMTime(5.0) != MMTime(5.0)); + CHECK(MMTime(3.0) > MMTime(2.0)); + CHECK(MMTime(3.0) >= MMTime(2.0)); + CHECK(MMTime(2.0) < MMTime(3.0)); + CHECK(MMTime(2.0) <= MMTime(3.0)); } - -TEST(MMTimeTests, FromNumbers) +TEST_CASE("MMTime from numbers", "[MMTime]") { - ASSERT_EQ(MMTime(1.0), MMTime::fromUs(1)); - ASSERT_EQ(MMTime(1'000.0), MMTime::fromMs(1)); - ASSERT_EQ(MMTime(1'000'000.0), MMTime::fromSeconds(1)); + CHECK(MMTime::fromUs(1) == MMTime(1.0)); + CHECK(MMTime::fromMs(1) == MMTime(1'000.0)); + CHECK(MMTime::fromSeconds(1) == MMTime(1'000'000.0)); } - -TEST(MMTimeTests, ToNumbers) +TEST_CASE("MMTime to umbers", "[MMTime]") { - ASSERT_DOUBLE_EQ(1.0, MMTime(1.0).getUsec()); - ASSERT_DOUBLE_EQ(1.0, MMTime(1000.0).getMsec()); -} \ No newline at end of file + CHECK(MMTime(1.0).getUsec() == 1.0); + CHECK(MMTime(1000.0).getMsec() == 1.0); +} + +} // namespace MM \ No newline at end of file diff --git a/MMDevice/unittest/meson.build b/MMDevice/unittest/meson.build index 603a26673..7c4f77276 100644 --- a/MMDevice/unittest/meson.build +++ b/MMDevice/unittest/meson.build @@ -1,8 +1,11 @@ # This Meson script is experimental and potentially incomplete. It is not part # of the supported build system for Micro-Manager or mmCoreAndDevices. -gtest_proj = subproject('gtest') -gtest_dep = gtest_proj.get_variable('gtest_main_dep') +catch2_with_main_dep = dependency( + 'catch2-with-main', + allow_fallback: true, + include_type: 'system', +) mmdevice_test_sources = files( 'FloatPropertyTruncation-Tests.cpp', @@ -14,7 +17,7 @@ mmdevice_test_exe = executable( sources: mmdevice_test_sources, include_directories: mmdevice_include_dir, link_with: mmdevice_lib, - dependencies: gtest_dep, + dependencies: catch2_with_main_dep, ) test( From b4a80f1361059e29804be67f95f58956938dd464 Mon Sep 17 00:00:00 2001 From: "Mark A. Tsuchida" Date: Mon, 18 Dec 2023 16:48:30 -0600 Subject: [PATCH 4/4] MMCore: Switch from GoogleTest to Catch2 --- MMCore/subprojects/.gitignore | 2 +- MMCore/subprojects/catch2.wrap | 11 + MMCore/subprojects/gtest.wrap | 16 - MMCore/unittest/APIError-Tests.cpp | 78 ++--- MMCore/unittest/CoreCreateDestroy-Tests.cpp | 25 ++ MMCore/unittest/CoreSanity-Tests.cpp | 25 -- MMCore/unittest/Logger-Tests.cpp | 21 +- .../LoggingSplitEntryIntoLines-Tests.cpp | 331 ++++++++---------- MMCore/unittest/meson.build | 11 +- 9 files changed, 239 insertions(+), 281 deletions(-) create mode 100644 MMCore/subprojects/catch2.wrap delete mode 100644 MMCore/subprojects/gtest.wrap create mode 100644 MMCore/unittest/CoreCreateDestroy-Tests.cpp delete mode 100644 MMCore/unittest/CoreSanity-Tests.cpp diff --git a/MMCore/subprojects/.gitignore b/MMCore/subprojects/.gitignore index 479f9fa9c..a1beaa0c5 100644 --- a/MMCore/subprojects/.gitignore +++ b/MMCore/subprojects/.gitignore @@ -9,4 +9,4 @@ /*.wrap # Do not ignore wraps we provide -!/gtest.wrap \ No newline at end of file +!/catch2.wrap diff --git a/MMCore/subprojects/catch2.wrap b/MMCore/subprojects/catch2.wrap new file mode 100644 index 000000000..691d39c85 --- /dev/null +++ b/MMCore/subprojects/catch2.wrap @@ -0,0 +1,11 @@ +[wrap-file] +directory = Catch2-3.4.0 +source_url = https://github.com/catchorg/Catch2/archive/v3.4.0.tar.gz +source_filename = Catch2-3.4.0.tar.gz +source_hash = 122928b814b75717316c71af69bd2b43387643ba076a6ec16e7882bfb2dfacbb +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/catch2_3.4.0-1/Catch2-3.4.0.tar.gz +wrapdb_version = 3.4.0-1 + +[provide] +catch2 = catch2_dep +catch2-with-main = catch2_with_main_dep diff --git a/MMCore/subprojects/gtest.wrap b/MMCore/subprojects/gtest.wrap deleted file mode 100644 index 8c067ff20..000000000 --- a/MMCore/subprojects/gtest.wrap +++ /dev/null @@ -1,16 +0,0 @@ -[wrap-file] -directory = googletest-1.14.0 -source_url = https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz -source_filename = gtest-1.14.0.tar.gz -source_hash = 8ad598c73ad796e0d8280b082cebd82a630d73e73cd3c70057938a6501bba5d7 -patch_filename = gtest_1.14.0-1_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/gtest_1.14.0-1/get_patch -patch_hash = 2e693c7d3f9370a7aa6dac802bada0874d3198ad4cfdf75647b818f691182b50 -source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/gtest_1.14.0-1/gtest-1.14.0.tar.gz -wrapdb_version = 1.14.0-1 - -[provide] -gtest = gtest_dep -gtest_main = gtest_main_dep -gmock = gmock_dep -gmock_main = gmock_main_dep diff --git a/MMCore/unittest/APIError-Tests.cpp b/MMCore/unittest/APIError-Tests.cpp index 66ab0df2e..767daa9db 100644 --- a/MMCore/unittest/APIError-Tests.cpp +++ b/MMCore/unittest/APIError-Tests.cpp @@ -1,8 +1,8 @@ -#include +#include #include "MMCore.h" -TEST(APIErrorTests, SetFocusDirectionWithInvalidDevice) +TEST_CASE("setFocusDirection with invalid device", "[APIError]") { CMMCore c; // Must not throw or crash @@ -20,68 +20,68 @@ TEST(APIErrorTests, SetFocusDirectionWithInvalidDevice) c.setFocusDirection("Core", -1); } -TEST(APIErrorTests, GetNumberOfStatesWithInvalidDevice) +TEST_CASE("getNumberOfStates with invalid device", "[APIError]") { CMMCore c; // Must not throw or crash - EXPECT_EQ(-1, c.getNumberOfStates(nullptr)); - EXPECT_EQ(-1, c.getNumberOfStates("")); - EXPECT_EQ(-1, c.getNumberOfStates("Blah")); - EXPECT_EQ(-1, c.getNumberOfStates("Core")); + CHECK(c.getNumberOfStates(nullptr) == -1); + CHECK(c.getNumberOfStates("") == -1); + CHECK(c.getNumberOfStates("Blah") == -1); + CHECK(c.getNumberOfStates("Core") == -1); } -TEST(APIErrorTests, GetAvailableConfigsWithInvalidGroup) +TEST_CASE("getAvailableConfigs with invalid group", "[APIError]") { CMMCore c; - EXPECT_TRUE(c.getAvailableConfigs(nullptr).empty()); - EXPECT_TRUE(c.getAvailableConfigs("").empty()); - EXPECT_TRUE(c.getAvailableConfigs("Blah").empty()); + CHECK(c.getAvailableConfigs(nullptr).empty()); + CHECK(c.getAvailableConfigs("").empty()); + CHECK(c.getAvailableConfigs("Blah").empty()); } -TEST(APIErrorTests, GetPixelSizeUmWithNoConfig) +TEST_CASE("getPixelSizeUm with no config", "[APIError]") { CMMCore c; - EXPECT_EQ(0.0, c.getPixelSizeUm(false)); - EXPECT_EQ(0.0, c.getPixelSizeUm(true)); + CHECK(c.getPixelSizeUm(false) == 0.0); + CHECK(c.getPixelSizeUm(true) == 0.0); } -TEST(APIErrorTests, IsConfigDefinedWithNullArgs) +TEST_CASE("isConfigDefined with null args", "[APIError]") { CMMCore c; - EXPECT_FALSE(c.isConfigDefined(nullptr, "Blah")); - EXPECT_FALSE(c.isConfigDefined("Blah", nullptr)); - EXPECT_FALSE(c.isConfigDefined(nullptr, nullptr)); - EXPECT_FALSE(c.isConfigDefined("Blah", "Blah")); - EXPECT_FALSE(c.isConfigDefined(nullptr, "")); - EXPECT_FALSE(c.isConfigDefined("", nullptr)); - EXPECT_FALSE(c.isConfigDefined(nullptr, nullptr)); - EXPECT_FALSE(c.isConfigDefined("", "")); - EXPECT_FALSE(c.isConfigDefined("", "Blah")); - EXPECT_FALSE(c.isConfigDefined("Blah", "")); + CHECK_FALSE(c.isConfigDefined(nullptr, "Blah")); + CHECK_FALSE(c.isConfigDefined("Blah", nullptr)); + CHECK_FALSE(c.isConfigDefined(nullptr, nullptr)); + CHECK_FALSE(c.isConfigDefined("Blah", "Blah")); + CHECK_FALSE(c.isConfigDefined(nullptr, "")); + CHECK_FALSE(c.isConfigDefined("", nullptr)); + CHECK_FALSE(c.isConfigDefined(nullptr, nullptr)); + CHECK_FALSE(c.isConfigDefined("", "")); + CHECK_FALSE(c.isConfigDefined("", "Blah")); + CHECK_FALSE(c.isConfigDefined("Blah", "")); } -TEST(APIErrorTests, IsGroupDefinedWithNullArg) +TEST_CASE("isGroupDefined with null arg", "[APIError]") { CMMCore c; - EXPECT_FALSE(c.isGroupDefined(nullptr)); - EXPECT_FALSE(c.isGroupDefined("")); - EXPECT_FALSE(c.isGroupDefined("Blah")); + CHECK_FALSE(c.isGroupDefined(nullptr)); + CHECK_FALSE(c.isGroupDefined("")); + CHECK_FALSE(c.isGroupDefined("Blah")); } -TEST(APIErrorTests, SupportsDeviceDetectionWithInvalidDevice) +TEST_CASE("supportsDeviceDetection with invalid device", "[APIError]") { CMMCore c; - EXPECT_FALSE(c.supportsDeviceDetection(nullptr)); - EXPECT_FALSE(c.supportsDeviceDetection("")); - EXPECT_FALSE(c.supportsDeviceDetection("Blah")); - EXPECT_FALSE(c.supportsDeviceDetection("Core")); + CHECK_FALSE(c.supportsDeviceDetection(nullptr)); + CHECK_FALSE(c.supportsDeviceDetection("")); + CHECK_FALSE(c.supportsDeviceDetection("Blah")); + CHECK_FALSE(c.supportsDeviceDetection("Core")); } -TEST(APIErrorTests, DetectDeviceWithInvalidDevice) +TEST_CASE("detectDevice with invalid device", "[APIError]") { CMMCore c; - EXPECT_EQ(MM::Unimplemented, c.detectDevice(nullptr)); - EXPECT_EQ(MM::Unimplemented, c.detectDevice("")); - EXPECT_EQ(MM::Unimplemented, c.detectDevice("Blah")); - EXPECT_EQ(MM::Unimplemented, c.detectDevice("Core")); + CHECK(c.detectDevice(nullptr) == MM::Unimplemented); + CHECK(c.detectDevice("") == MM::Unimplemented); + CHECK(c.detectDevice("Blah") == MM::Unimplemented); + CHECK(c.detectDevice("Core") == MM::Unimplemented); } \ No newline at end of file diff --git a/MMCore/unittest/CoreCreateDestroy-Tests.cpp b/MMCore/unittest/CoreCreateDestroy-Tests.cpp new file mode 100644 index 000000000..45abbbe55 --- /dev/null +++ b/MMCore/unittest/CoreCreateDestroy-Tests.cpp @@ -0,0 +1,25 @@ +#include + +#include "MMCore.h" + +TEST_CASE("CMMCore create and destroy twice", "[CoreCreateDestroy]") +{ + { + CMMCore c1; + } + { + CMMCore c2; + } +} + +TEST_CASE("CMMCore create two at once", "[CoreCreateDestroy]") +{ + CMMCore c1; + CMMCore c2; +} + +TEST_CASE("CMMCore create and reset", "[CoreCreateDestroy]") +{ + CMMCore c; + c.reset(); +} \ No newline at end of file diff --git a/MMCore/unittest/CoreSanity-Tests.cpp b/MMCore/unittest/CoreSanity-Tests.cpp deleted file mode 100644 index 4abb5f5a2..000000000 --- a/MMCore/unittest/CoreSanity-Tests.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include - -#include "MMCore.h" - -TEST(CoreSanityTests, CreateAndDestroyTwice) -{ - { - CMMCore c1; - } - { - CMMCore c2; - } -} - -TEST(CoreSanityTests, CreateTwoAtOnce) -{ - CMMCore c1; - CMMCore c2; -} - -TEST(CoreSanityTests, CreateAndReset) -{ - CMMCore c; - c.reset(); -} \ No newline at end of file diff --git a/MMCore/unittest/Logger-Tests.cpp b/MMCore/unittest/Logger-Tests.cpp index 7da24b8c9..e1b6d0922 100644 --- a/MMCore/unittest/Logger-Tests.cpp +++ b/MMCore/unittest/Logger-Tests.cpp @@ -1,4 +1,4 @@ -#include +#include #include "Logging/Logging.h" @@ -8,10 +8,10 @@ #include #include -using namespace mm::logging; +namespace mm { +namespace logging { - -TEST(LoggerTests, BasicSynchronous) +TEST_CASE("synchronous logger basics", "[Logger]") { std::shared_ptr c = std::make_shared(); @@ -26,7 +26,7 @@ TEST(LoggerTests, BasicSynchronous) } -TEST(LoggerTests, BasicAsynchronous) +TEST_CASE("asynchronous logger basics", "[Logger]") { std::shared_ptr c = std::make_shared(); @@ -41,7 +41,7 @@ TEST(LoggerTests, BasicAsynchronous) } -TEST(LoggerTests, BasicLogStream) +TEST_CASE("log stream basics", "[Logger]") { std::shared_ptr c = std::make_shared(); @@ -80,7 +80,7 @@ class LoggerTestThreadFunc }; -TEST(LoggerTests, SyncAndThreaded) +TEST_CASE("sync logger on thread", "[Logger]") { std::shared_ptr c = std::make_shared(); @@ -100,7 +100,7 @@ TEST(LoggerTests, SyncAndThreaded) } -TEST(LoggerTests, AsyncAndThreaded) +TEST_CASE("async logger on thread", "[Logger]") { std::shared_ptr c = std::make_shared(); @@ -117,4 +117,7 @@ TEST(LoggerTests, AsyncAndThreaded) } for (unsigned i = 0; i < threads.size(); ++i) threads[i]->join(); -} \ No newline at end of file +} + +} // namespace logging +} // namespace mm \ No newline at end of file diff --git a/MMCore/unittest/LoggingSplitEntryIntoLines-Tests.cpp b/MMCore/unittest/LoggingSplitEntryIntoLines-Tests.cpp index 917bbe3a8..8ec4bab84 100644 --- a/MMCore/unittest/LoggingSplitEntryIntoLines-Tests.cpp +++ b/MMCore/unittest/LoggingSplitEntryIntoLines-Tests.cpp @@ -1,4 +1,4 @@ -#include +#include #include "Logging/GenericLinePacket.h" #include "Logging/Logging.h" @@ -9,214 +9,171 @@ #include #include -using namespace mm::logging; +namespace mm { +namespace logging { -typedef Metadata MetadataType; -typedef internal::GenericPacketArray PacketArrayType; -const size_t MaxLogLineLen = - internal::GenericLinePacket::PacketTextLen; - - -class SplitEntryIntoPacketsTest : public ::testing::Test +TEST_CASE("split entry into lines", "[Logging]") { -public: - SplitEntryIntoPacketsTest() : - loggerData_("component"), - entryData_(LogLevelInfo) - {} + Metadata::LoggerDataType loggerData("component"); + Metadata::EntryDataType entryData(LogLevelInfo); + Metadata::StampDataType stampData; + stampData.Stamp(); -protected: - MetadataType::LoggerDataType loggerData_; - MetadataType::EntryDataType entryData_; - MetadataType::StampDataType stampData_; - - std::vector< internal::GenericLinePacket > result_; - virtual void SetUp() + SECTION("empty result") { - stampData_.Stamp(); - } - virtual void Split(const char* s) - { - PacketArrayType array; - array.AppendEntry(loggerData_, entryData_, stampData_, s); - std::copy(array.Begin(), array.End(), std::back_inserter(result_)); + const char *testStr = GENERATE( + "", "\r", "\n", "\r\r", "\r\n", "\n\n", + "\r\r\r", "\r\r\n", "\r\n\r", "\r\n\n", + "\n\r\r", "\n\r\n", "\n\n\r", "\n\n\n"); + internal::GenericPacketArray array; + array.AppendEntry(loggerData, entryData, stampData, testStr); + std::vector> result; + std::copy(array.Begin(), array.End(), std::back_inserter(result)); + CHECK(result.size() == 1); + CHECK_THAT(result[0].GetText(), Catch::Matchers::Equals("")); } -}; - -class SplitEntryIntoPacketsParameterizedTest : - public SplitEntryIntoPacketsTest, - public ::testing::WithParamInterface -{ - virtual void SetUp() + SECTION("single-char result") { - SplitEntryIntoPacketsTest::SetUp(); - Split(GetParam().c_str()); - } -}; - - -class SplitEntryIntoPacketsEmptyResultTest : - public SplitEntryIntoPacketsParameterizedTest -{}; - -TEST_P(SplitEntryIntoPacketsEmptyResultTest, EmptyResult) -{ - ASSERT_EQ(1, result_.size()); - EXPECT_STREQ("", result_[0].GetText()); -} - -INSTANTIATE_TEST_SUITE_P(NewlinesCase, SplitEntryIntoPacketsEmptyResultTest, - ::testing::Values("", "\r", "\n", "\r\r", "\r\n", "\n\n", - "\r\r\r", "\r\r\n", "\r\n\r", "\r\n\n", - "\n\r\r", "\n\r\n", "\n\n\r", "\n\n\n")); - - -class SplitEntryIntoPacketsSingleCharResultTest : - public SplitEntryIntoPacketsParameterizedTest -{}; - -TEST_P(SplitEntryIntoPacketsSingleCharResultTest, SingleXResult) -{ - ASSERT_EQ(1, result_.size()); - EXPECT_STREQ("X", result_[0].GetText()); -} - -INSTANTIATE_TEST_SUITE_P(XFollowedByNewlinesCase, - SplitEntryIntoPacketsSingleCharResultTest, - ::testing::Values("X", "X\r", "X\n", "X\r\r", "X\r\n", "X\n\n", + const char *testStr = GENERATE( + "X", "X\r", "X\n", "X\r\r", "X\r\n", "X\n\n", "X\r\r\r", "X\r\r\n", "X\r\n\r", "X\r\n\n", - "X\n\r\r", "X\n\r\n", "X\n\n\r", "X\n\n\n")); - - -class SplitEntryIntoPacketsTwoLineResultTest : - public SplitEntryIntoPacketsParameterizedTest -{}; - -TEST_P(SplitEntryIntoPacketsTwoLineResultTest, TwoLineXYResult) -{ - ASSERT_EQ(2, result_.size()); - EXPECT_EQ(internal::PacketStateEntryFirstLine, result_[0].GetPacketState()); - EXPECT_STREQ("X", result_[0].GetText()); - EXPECT_EQ(internal::PacketStateNewLine, result_[1].GetPacketState()); - EXPECT_STREQ("Y", result_[1].GetText()); -} - -INSTANTIATE_TEST_SUITE_P(XNewlineYCase, - SplitEntryIntoPacketsTwoLineResultTest, - ::testing::Values("X\rY", "X\nY", "X\r\nY")); + "X\n\r\r", "X\n\r\n", "X\n\n\r", "X\n\n\n"); + internal::GenericPacketArray array; + array.AppendEntry(loggerData, entryData, stampData, testStr); + std::vector> result; + std::copy(array.Begin(), array.End(), std::back_inserter(result)); + CHECK(result.size() == 1); + CHECK_THAT(result[0].GetText(), Catch::Matchers::Equals("X")); + } -INSTANTIATE_TEST_SUITE_P(XLinefeedYNewlinesCase, - SplitEntryIntoPacketsTwoLineResultTest, - ::testing::Values("X\nY\r", "X\nY\n", "X\nY\r\r", "X\nY\r\n", "X\nY\n\n", + SECTION("two-line result") + { + const char *testStr = GENERATE( + "X\rY", "X\nY", "X\r\nY", + "X\nY\r", "X\nY\n", "X\nY\r\r", "X\nY\r\n", "X\nY\n\n", "X\nY\r\r\r", "X\nY\r\r\n", "X\nY\r\n\r", "X\nY\r\n\n", - "X\nY\n\r\r", "X\nY\n\r\n", "X\nY\n\n\r", "X\nY\n\n\n")); - - -class SplitEntryIntoPacketsXEmptyYResultTest : - public SplitEntryIntoPacketsParameterizedTest -{}; - -TEST_P(SplitEntryIntoPacketsXEmptyYResultTest, XEmptyYResult) -{ - ASSERT_EQ(3, result_.size()); - EXPECT_EQ(internal::PacketStateEntryFirstLine, result_[0].GetPacketState()); - EXPECT_STREQ("X", result_[0].GetText()); - EXPECT_EQ(internal::PacketStateNewLine, result_[1].GetPacketState()); - EXPECT_STREQ("", result_[1].GetText()); - EXPECT_EQ(internal::PacketStateNewLine, result_[2].GetPacketState()); - EXPECT_STREQ("Y", result_[2].GetText()); -} - -INSTANTIATE_TEST_SUITE_P(XNewlineNewlineYCase, - SplitEntryIntoPacketsXEmptyYResultTest, - ::testing::Values("X\r\rY", "X\n\nY", "X\n\rY", - "X\r\n\rY", "X\r\n\nY", "X\r\r\nY", "X\n\r\nY", - "X\r\n\r\nY")); - - -class SplitEntryIntoPacketsLeadingNewlineTest : - public SplitEntryIntoPacketsTest, - public ::testing::WithParamInterface< std::pair > -{ -protected: - size_t expected_; + "X\nY\n\r\r", "X\nY\n\r\n", "X\nY\n\n\r", "X\nY\n\n\n"); + internal::GenericPacketArray array; + array.AppendEntry(loggerData, entryData, stampData, testStr); + std::vector> result; + std::copy(array.Begin(), array.End(), std::back_inserter(result)); + CHECK(result.size() == 2); + CHECK(result[0].GetPacketState() == internal::PacketStateEntryFirstLine); + CHECK_THAT(result[0].GetText(), Catch::Matchers::Equals("X")); + CHECK(result[1].GetPacketState() == internal::PacketStateNewLine); + CHECK_THAT(result[1].GetText(), Catch::Matchers::Equals("Y")); + } - virtual void SetUp() + SECTION("three-line result with empty middle line") { - SplitEntryIntoPacketsTest::SetUp(); - expected_ = GetParam().first; - Split(GetParam().second.c_str()); + const char *testStr = GENERATE( + "X\r\rY", "X\n\nY", "X\n\rY", "X\r\n\rY", "X\r\n\nY", + "X\r\r\nY", "X\n\r\nY", "X\r\n\r\nY"); + internal::GenericPacketArray array; + array.AppendEntry(loggerData, entryData, stampData, testStr); + std::vector> result; + std::copy(array.Begin(), array.End(), std::back_inserter(result)); + CHECK(result.size() == 3); + CHECK(result[0].GetPacketState() == internal::PacketStateEntryFirstLine); + CHECK_THAT(result[0].GetText(), Catch::Matchers::Equals("X")); + CHECK(result[1].GetPacketState() == internal::PacketStateNewLine); + CHECK_THAT(result[1].GetText(), Catch::Matchers::Equals("")); + CHECK(result[2].GetPacketState() == internal::PacketStateNewLine); + CHECK_THAT(result[2].GetText(), Catch::Matchers::Equals("Y")); } -}; -TEST_P(SplitEntryIntoPacketsLeadingNewlineTest, CorrectLeadingNewlines) -{ - ASSERT_EQ(expected_ + 1, result_.size()); - EXPECT_EQ(internal::PacketStateEntryFirstLine, result_[0].GetPacketState()); - for (size_t i = 0; i < expected_; ++i) + SECTION("one leading newline") { - EXPECT_STREQ("", result_[i].GetText()); - EXPECT_EQ(internal::PacketStateNewLine, result_[i + 1].GetPacketState()); + const char *testStr = GENERATE("\rX", "\nX", "\r\nX"); + internal::GenericPacketArray array; + array.AppendEntry(loggerData, entryData, stampData, testStr); + std::vector> result; + std::copy(array.Begin(), array.End(), std::back_inserter(result)); + CHECK(result.size() == 2); + CHECK(result[0].GetPacketState() == internal::PacketStateEntryFirstLine); + CHECK_THAT(result[0].GetText(), Catch::Matchers::Equals("")); + CHECK(result[1].GetPacketState() == internal::PacketStateNewLine); + CHECK_THAT(result[1].GetText(), Catch::Matchers::Equals("X")); + } - EXPECT_STREQ("X", result_[expected_].GetText()); -} -INSTANTIATE_TEST_SUITE_P(LeadingNewlinesCase, - SplitEntryIntoPacketsLeadingNewlineTest, - ::testing::Values(std::make_pair(0, "X"), - std::make_pair(1, "\rX"), - std::make_pair(1, "\nX"), - std::make_pair(1, "\r\nX"), - std::make_pair(2, "\r\rX"), - std::make_pair(2, "\n\rX"), - std::make_pair(2, "\n\nX"), - std::make_pair(2, "\r\n\rX"), - std::make_pair(2, "\r\n\nX"), - std::make_pair(2, "\r\r\nX"), - std::make_pair(2, "\n\r\nX"))); + SECTION("two leading newlines") + { + const char *testStr = GENERATE( + "\r\rX", "\n\rX", "\n\nX", "\r\n\rX", "\r\n\nX", + "\r\r\nX", "\n\r\nX"); + internal::GenericPacketArray array; + array.AppendEntry(loggerData, entryData, stampData, testStr); + std::vector> result; + std::copy(array.Begin(), array.End(), std::back_inserter(result)); + CHECK(result.size() == 3); + CHECK(result[0].GetPacketState() == internal::PacketStateEntryFirstLine); + CHECK_THAT(result[0].GetText(), Catch::Matchers::Equals("")); + CHECK(result[1].GetPacketState() == internal::PacketStateNewLine); + CHECK_THAT(result[1].GetText(), Catch::Matchers::Equals("")); + CHECK(result[2].GetPacketState() == internal::PacketStateNewLine); + CHECK_THAT(result[2].GetText(), Catch::Matchers::Equals("X")); + } + SECTION("soft newlines") + { + static const std::size_t MaxLogLineLen = + internal::GenericLinePacket::PacketTextLen; + SECTION("no soft split") + { + std::size_t repeatCount = GENERATE(MaxLogLineLen - 1, MaxLogLineLen); + std::string testStr(repeatCount, 'x'); + internal::GenericPacketArray array; + array.AppendEntry(loggerData, entryData, stampData, testStr.c_str()); + std::vector> result; + std::copy(array.Begin(), array.End(), std::back_inserter(result)); + CHECK(result.size() == 1); + CHECK(result[0].GetPacketState() == internal::PacketStateEntryFirstLine); + CHECK(result[0].GetText() == testStr); + } -class SplitEntryIntoPacketsSoftNewlineTest : - public SplitEntryIntoPacketsParameterizedTest -{}; + SECTION("one soft split") + { + std::size_t charCount = GENERATE( + MaxLogLineLen + 1, + 2 * MaxLogLineLen - 1, + 2 * MaxLogLineLen); + std::string testStr(charCount, 'x'); + internal::GenericPacketArray array; + array.AppendEntry(loggerData, entryData, stampData, testStr.c_str()); + std::vector> result; + std::copy(array.Begin(), array.End(), std::back_inserter(result)); + CHECK(result.size() == 2); + CHECK(result[0].GetPacketState() == internal::PacketStateEntryFirstLine); + CHECK(result[0].GetText() == std::string(MaxLogLineLen, 'x')); + CHECK(result[1].GetPacketState() == internal::PacketStateLineContinuation); + CHECK(result[1].GetText() == + std::string(testStr.size() - MaxLogLineLen, 'x')); + } -TEST_P(SplitEntryIntoPacketsSoftNewlineTest, CorrectSplit) -{ - // We are assuming input did not contain hard newlines - size_t inputLen = GetParam().size(); - size_t nLines = inputLen ? (inputLen - 1) / MaxLogLineLen + 1 : 1; - ASSERT_EQ(nLines, result_.size()); - EXPECT_EQ(internal::PacketStateEntryFirstLine, result_[0].GetPacketState()); - for (size_t i = 0; i < nLines; ++i) - { - if (i > 0) + SECTION("two soft splits") { - EXPECT_EQ(internal::PacketStateLineContinuation, - result_[i].GetPacketState()); + std::size_t charCount = GENERATE( + 2 * MaxLogLineLen + 1, + 3 * MaxLogLineLen - 1, + 3 * MaxLogLineLen); + std::string testStr(charCount, 'x'); + internal::GenericPacketArray array; + array.AppendEntry(loggerData, entryData, stampData, testStr.c_str()); + std::vector> result; + std::copy(array.Begin(), array.End(), std::back_inserter(result)); + CHECK(result.size() == 3); + CHECK(result[0].GetPacketState() == internal::PacketStateEntryFirstLine); + CHECK(result[0].GetText() == std::string(MaxLogLineLen, 'x')); + CHECK(result[1].GetPacketState() == internal::PacketStateLineContinuation); + CHECK(result[1].GetText() == std::string(MaxLogLineLen, 'x')); + CHECK(result[2].GetPacketState() == internal::PacketStateLineContinuation); + CHECK(result[2].GetText() == + std::string(testStr.size() - 2 * MaxLogLineLen, 'x')); } - EXPECT_STREQ( - GetParam().substr(i * MaxLogLineLen, MaxLogLineLen).c_str(), - result_[i].GetText()); } } -INSTANTIATE_TEST_SUITE_P(NoSoftSplitCase, - SplitEntryIntoPacketsSoftNewlineTest, - ::testing::Values( - std::string(MaxLogLineLen - 1, 'x'), - std::string(MaxLogLineLen, 'x'))); - -INSTANTIATE_TEST_SUITE_P(OneSoftSplitCase, - SplitEntryIntoPacketsSoftNewlineTest, - ::testing::Values( - std::string(MaxLogLineLen + 1, 'x'), - std::string(2 * MaxLogLineLen - 1, 'x'), - std::string(2 * MaxLogLineLen, 'x'))); - -INSTANTIATE_TEST_SUITE_P(TwoSoftSplitCase, - SplitEntryIntoPacketsSoftNewlineTest, - ::testing::Values( - std::string(2 * MaxLogLineLen + 1, 'x'), - std::string(3 * MaxLogLineLen - 1, 'x'), - std::string(3 * MaxLogLineLen, 'x'))); \ No newline at end of file +} // namespace logging +} // namespace mm \ No newline at end of file diff --git a/MMCore/unittest/meson.build b/MMCore/unittest/meson.build index 92ca4b566..416d51109 100644 --- a/MMCore/unittest/meson.build +++ b/MMCore/unittest/meson.build @@ -1,12 +1,15 @@ # This Meson script is experimental and potentially incomplete. It is not part # of the supported build system for Micro-Manager or mmCoreAndDevices. -gtest_proj = subproject('gtest') -gtest_dep = gtest_proj.get_variable('gtest_main_dep') +catch2_with_main_dep = dependency( + 'catch2-with-main', + allow_fallback: true, + include_type: 'system', +) mmcore_test_sources = files( 'APIError-Tests.cpp', - 'CoreSanity-Tests.cpp', + 'CoreCreateDestroy-Tests.cpp', 'Logger-Tests.cpp', 'LoggingSplitEntryIntoLines-Tests.cpp', ) @@ -18,7 +21,7 @@ mmcore_test_exe = executable( link_with: mmcore_lib, dependencies: [ mmdevice_dep, - gtest_dep, + catch2_with_main_dep, ], cpp_args: [ '-D_CRT_SECURE_NO_WARNINGS', # TODO Eliminate the need