[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master 440c67d 2/6: Add a null_stream unit test
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master 440c67d 2/6: Add a null_stream unit test |
Date: |
Thu, 5 Aug 2021 17:09:59 -0400 (EDT) |
branch: master
commit 440c67d12164bedc1f1c4603246178c99cd068cd
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>
Add a null_stream unit test
Using a std::stringstream with badbit set, or a std::fstream with no
associated file (whether or not badbit is set), is fast and simple.
Techniques that set badbit aren't appropriate for code that tests
operations to make sure they succeed, as they will instead fail.
Another problem with all these techniques is that they might not
work: Kühl noted in 1999 that "some implementations have minor bugs
and do not always consider the flags correctly", and there were still
defects many years later--see, e.g., the comment to this article:
https://stackoverflow.com/a/8244052
that refers to this defect addressed only in 2017:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53984
The null-stream technique, derived from Dietmar Kühl's work, is much
slower because of its construction overhead; but it's as fast as the
others if it's constructed OAOO. (The OAOO approach currently used by
lmi happens to set badbit, which therefore seems not to be a problem
in practice after all.)
The /dev/null technique is too slow.
---
Makefile.am | 4 ++
null_stream_test.cpp | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++
objects.make | 7 +++
3 files changed, 183 insertions(+)
diff --git a/Makefile.am b/Makefile.am
index cc24612..24c87a1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -140,6 +140,7 @@ TESTS = \
mortality_rates_test \
name_value_pairs_test \
ncnnnpnn_test \
+ null_stream_test \
numeric_io_test \
path_utility_test \
premium_tax_test \
@@ -941,6 +942,9 @@ name_value_pairs_test_LDADD = \
ncnnnpnn_test_LDADD = \
libtest_common.la
+null_stream_test_LDADD = \
+ libtest_common.la
+
numeric_io_test_LDADD = \
libtest_common.la \
$(BOOST_LIBS)
diff --git a/null_stream_test.cpp b/null_stream_test.cpp
new file mode 100644
index 0000000..37cbb80
--- /dev/null
+++ b/null_stream_test.cpp
@@ -0,0 +1,172 @@
+// Stream and stream buffer that discard output--unit test.
+//
+// Copyright (C) 2021 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
+//
+// https://savannah.nongnu.org/projects/lmi
+// email: <gchicares@sbcglobal.net>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+#include "pchfile.hpp"
+
+#include "null_stream.hpp"
+
+#include "miscellany.hpp" // ios_out_app_binary()
+#include "test_tools.hpp"
+#include "timer.hpp"
+
+#include <fstream>
+#include <iomanip>
+#include <sstream>
+
+void emit_text_to_stream(std::ostream& os)
+{
+ for(int i = 0; i < 10; ++i)
+ {
+ os
+ << "The Beaver had counted with scrupulous care,\n"
+ << " Attending to every word:\n"
+ << "But it fairly lost heart, and outgrabe in despair,\n"
+ << " When the third repetition occurred.\n"
+ << std::flush
+ ;
+ os
+ << std::setprecision(21)
+ << std::setw(12) << 3.14159
+ << std::fixed
+ << std::hex
+ << std::hexfloat
+ << std::setw(12) << 3.14159
+ << std::endl
+ ;
+ }
+}
+
+/// Test writing to '/dev/null'.
+///
+/// Not every OS has '/dev/null', but for msw, using 'NUL' doesn't
+/// make this any faster.
+
+void mete_dev_null()
+{
+ for(int i = 0; i < 1e4; ++i)
+ {
+ std::ofstream ofs("/dev/null", ios_out_app_binary());
+ emit_text_to_stream(ofs);
+ }
+}
+
+// Test writing to null stream derived from Dietmar Kühl's work.
+
+void mete_kuehl()
+{
+ for(int i = 0; i < 1e4; ++i)
+ {
+ std::ostream os(&null_streambuf());
+ emit_text_to_stream(os);
+ }
+}
+
+// Test writing to static null stream.
+
+void mete_kuehl_static()
+{
+ for(int i = 0; i < 1e4; ++i)
+ {
+ emit_text_to_stream(null_stream());
+ }
+}
+
+/// Test writing to an unopened ofstream.
+
+void mete_unopened_fstream()
+{
+ for(int i = 0; i < 1e4; ++i)
+ {
+ std::ofstream ofs;
+ emit_text_to_stream(ofs);
+ }
+}
+
+/// Test writing to an ofstream with 'badbit' set.
+
+void mete_badbit_fstream()
+{
+ for(int i = 0; i < 1e4; ++i)
+ {
+ std::ofstream ofs;
+ ofs.setstate(std::ios_base::badbit);
+ emit_text_to_stream(ofs);
+ }
+}
+
+/// Test writing to an ofstream with 'badbit' set.
+
+void mete_badbit_sstream()
+{
+ for(int i = 0; i < 1e4; ++i)
+ {
+ std::ostringstream oss;
+ oss.setstate(std::ios_base::badbit);
+ emit_text_to_stream(oss);
+ }
+}
+
+void test_fundamentals()
+{
+ // This shouldn't appear anywhere. Of course, there's no way to
+ // verify its absence everywhere.
+ std::ostream& os0 = null_stream();
+ os0
+ << "'But oh, beamish nephew, beware of the day,\n"
+ << " If your Snark be a Boojum! For then\n"
+ << "You will softly and suddenly vanish away,\n"
+ << " and never be met with again!'\n"
+ << std::flush
+ ;
+
+ // This alternative explicitly constructs a std::ostream each time
+ // it's used, which is costlier.
+ std::ostream os1(&null_streambuf());
+ os1
+ << "But if ever I meet with a Boojum, that day,\n"
+ << " In a moment (of this I am sure),\n"
+ << "I shall softly and suddenly vanish away--\n"
+ << " And the notion I cannot endure!\n"
+ << std::flush
+ ;
+}
+
+void assay_speed()
+{
+ std::cout
+ << "\n Speed tests..."
+ << "\n /dev/null : " << TimeAnAliquot(mete_dev_null)
+ << "\n Kühl : " << TimeAnAliquot(mete_kuehl)
+ << "\n Kühl, static : " << TimeAnAliquot(mete_kuehl_static)
+ << "\n unopened fstream : " << TimeAnAliquot(mete_unopened_fstream)
+ << "\n fstream, badbit : " << TimeAnAliquot(mete_badbit_fstream)
+ << "\n sstream, badbit : " << TimeAnAliquot(mete_badbit_sstream)
+ << std::endl
+ ;
+}
+
+int test_main(int, char*[])
+{
+ test_fundamentals();
+ assay_speed();
+
+ return 0;
+}
diff --git a/objects.make b/objects.make
index 2621716..6f5bd85 100644
--- a/objects.make
+++ b/objects.make
@@ -433,6 +433,7 @@ unit_test_targets := \
mortality_rates_test \
name_value_pairs_test \
ncnnnpnn_test \
+ null_stream_test \
numeric_io_test \
path_utility_test \
premium_tax_test \
@@ -861,6 +862,12 @@ ncnnnpnn_test$(EXEEXT): \
$(common_test_objects) \
ncnnnpnn_test.o \
+null_stream_test$(EXEEXT): \
+ $(common_test_objects) \
+ null_stream.o \
+ null_stream_test.o \
+ timer.o \
+
numeric_io_test$(EXEEXT): \
$(common_test_objects) \
calendar_date.o \
- [lmi-commits] [lmi] master updated (7a6262f -> a102012), Greg Chicares, 2021/08/05
- [lmi-commits] [lmi] master 50c1d57 1/6: Don't write solve trace to statusbar, Greg Chicares, 2021/08/05
- [lmi-commits] [lmi] master 440c67d 2/6: Add a null_stream unit test,
Greg Chicares <=
- [lmi-commits] [lmi] master 52456de 3/6: Demonstrate the speed advantage of 'badbit', Greg Chicares, 2021/08/05
- [lmi-commits] [lmi] master 048b2cc 4/6: Demonstrate a peril, Greg Chicares, 2021/08/05
- [lmi-commits] [lmi] master 4bc0910 5/6: Test std::ostream(nullptr) as well, Greg Chicares, 2021/08/05
- [lmi-commits] [lmi] master a102012 6/6: Generally avoid using null_stream(), Greg Chicares, 2021/08/05