diff --git a/docs/command-line.md b/docs/command-line.md
index 1741eb8f84..77e969b0eb 100644
--- a/docs/command-line.md
+++ b/docs/command-line.md
@@ -222,6 +222,10 @@ available warnings
When set to ```yes``` Catch will report the duration of each test case, in milliseconds. Note that it does this regardless of whether a test case passes or fails. Note, also, the certain reporters (e.g. Junit) always report test case durations regardless of this option being set or not.
+
-D, --min-duration <value>
+
+When set, Catch will report the duration of each test case that took more than <value> seconds, in milliseconds.
+
## Load test names to run from a file
-f, --input-file <filename>
diff --git a/include/internal/catch_commandline.cpp b/include/internal/catch_commandline.cpp
index a4010850d0..673d3b70bc 100644
--- a/include/internal/catch_commandline.cpp
+++ b/include/internal/catch_commandline.cpp
@@ -170,6 +170,9 @@ namespace Catch {
| Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
["-d"]["--durations"]
( "show test durations" )
+ | Opt( config.minDuration, "seconds" )
+ ["-D"]["--min-duration"]
+ ( "show test durations for tests taking at least the given number of seconds" )
| Opt( loadTestNamesFromFile, "filename" )
["-f"]["--input-file"]
( "load test names to run from a file" )
diff --git a/include/internal/catch_config.cpp b/include/internal/catch_config.cpp
index 21cd62965b..252bec62ef 100644
--- a/include/internal/catch_config.cpp
+++ b/include/internal/catch_config.cpp
@@ -64,6 +64,7 @@ namespace Catch {
bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); }
bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); }
ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
+ double Config::minDuration() const { return m_data.minDuration; }
RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
unsigned int Config::rngSeed() const { return m_data.rngSeed; }
UseColour::YesOrNo Config::useColour() const { return m_data.useColour; }
diff --git a/include/internal/catch_config.hpp b/include/internal/catch_config.hpp
index 64d2c035f9..fd7de5b2d4 100644
--- a/include/internal/catch_config.hpp
+++ b/include/internal/catch_config.hpp
@@ -52,6 +52,7 @@ namespace Catch {
Verbosity verbosity = Verbosity::Normal;
WarnAbout::What warnings = WarnAbout::Nothing;
ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter;
+ double minDuration = -1;
RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder;
UseColour::YesOrNo useColour = UseColour::Auto;
WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
@@ -103,6 +104,7 @@ namespace Catch {
bool warnAboutMissingAssertions() const override;
bool warnAboutNoTests() const override;
ShowDurations::OrNot showDurations() const override;
+ double minDuration() const override;
RunTests::InWhatOrder runOrder() const override;
unsigned int rngSeed() const override;
UseColour::YesOrNo useColour() const override;
diff --git a/include/internal/catch_interfaces_config.h b/include/internal/catch_interfaces_config.h
index 8fb986be46..e9c2cf9662 100644
--- a/include/internal/catch_interfaces_config.h
+++ b/include/internal/catch_interfaces_config.h
@@ -69,6 +69,7 @@ namespace Catch {
virtual int abortAfter() const = 0;
virtual bool showInvisibles() const = 0;
virtual ShowDurations::OrNot showDurations() const = 0;
+ virtual double minDuration() const = 0;
virtual TestSpec const& testSpec() const = 0;
virtual bool hasTestFilters() const = 0;
virtual std::vector const& getTestsOrTags() const = 0;
diff --git a/include/reporters/catch_reporter_bases.cpp b/include/reporters/catch_reporter_bases.cpp
index fcbafef58b..271f90ca24 100644
--- a/include/reporters/catch_reporter_bases.cpp
+++ b/include/reporters/catch_reporter_bases.cpp
@@ -41,6 +41,13 @@ namespace Catch {
return std::string(buffer);
}
+ bool shouldShowDuration( IConfig const& config, double duration ) {
+ if( config.showDurations() == ShowDurations::Always )
+ return true;
+ double min = config.minDuration();
+ return min >= 0 && duration >= min;
+ }
+
std::string serializeFilters( std::vector const& container ) {
ReusableStringStream oss;
bool first = true;
diff --git a/include/reporters/catch_reporter_bases.hpp b/include/reporters/catch_reporter_bases.hpp
index 66a891ffd4..f53794f4d1 100644
--- a/include/reporters/catch_reporter_bases.hpp
+++ b/include/reporters/catch_reporter_bases.hpp
@@ -25,6 +25,8 @@ namespace Catch {
// Returns double formatted as %.3f (format expected on output)
std::string getFormattedDuration( double duration );
+ bool shouldShowDuration( IConfig const &, double duration );
+
std::string serializeFilters( std::vector const& container );
template
diff --git a/include/reporters/catch_reporter_compact.cpp b/include/reporters/catch_reporter_compact.cpp
index 017f521f48..e9c44ea6f2 100644
--- a/include/reporters/catch_reporter_compact.cpp
+++ b/include/reporters/catch_reporter_compact.cpp
@@ -275,8 +275,9 @@ class AssertionPrinter {
}
void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
- if (m_config->showDurations() == ShowDurations::Always) {
- stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+ double dur = _sectionStats.durationInSeconds;
+ if ( shouldShowDuration( *m_config, dur ) ) {
+ stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl;
}
}
diff --git a/include/reporters/catch_reporter_console.cpp b/include/reporters/catch_reporter_console.cpp
index 0fa399d586..4f74ccb320 100644
--- a/include/reporters/catch_reporter_console.cpp
+++ b/include/reporters/catch_reporter_console.cpp
@@ -418,8 +418,9 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
stream << "\nNo assertions in test case";
stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
}
- if (m_config->showDurations() == ShowDurations::Always) {
- stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+ double dur = _sectionStats.durationInSeconds;
+ if (shouldShowDuration(*m_config, dur)) {
+ stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl;
}
if (m_headerPrinted) {
m_headerPrinted = false;
diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt
index 08badb809a..cde25cbd3b 100644
--- a/projects/CMakeLists.txt
+++ b/projects/CMakeLists.txt
@@ -27,6 +27,7 @@ set(TEST_SOURCES
${SELF_TEST_DIR}/IntrospectiveTests/StringManip.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/ToString.tests.cpp
+ ${SELF_TEST_DIR}/TimingTests/Sleep.tests.cpp
${SELF_TEST_DIR}/UsageTests/Approx.tests.cpp
${SELF_TEST_DIR}/UsageTests/BDD.tests.cpp
${SELF_TEST_DIR}/UsageTests/Benchmark.tests.cpp
@@ -454,6 +455,9 @@ set_tests_properties(TestsInFile::InvalidTestNames-2 PROPERTIES PASS_REGULAR_EXP
add_test(NAME RandomTestOrdering COMMAND ${PYTHON_EXECUTABLE}
${CATCH_DIR}/projects/TestScripts/testRandomOrder.py $)
+add_test(NAME TestTimeThreshold COMMAND ${PYTHON_EXECUTABLE}
+ ${CATCH_DIR}/projects/TestScripts/testTimeThreshold.py $)
+
if (CATCH_USE_VALGRIND)
add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $)
add_test(NAME ValgrindListTests COMMAND valgrind --leak-check=full --error-exitcode=1 $ --list-tests --verbosity high)
diff --git a/projects/SelfTest/TimingTests/Sleep.tests.cpp b/projects/SelfTest/TimingTests/Sleep.tests.cpp
new file mode 100644
index 0000000000..5b9398748d
--- /dev/null
+++ b/projects/SelfTest/TimingTests/Sleep.tests.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2011 Two Blue Cubes Ltd. All rights reserved.
+ *
+ * Distributed under the Boost Software License, Version 1.0. (See accompanying
+ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+#include "catch.hpp"
+
+#include
+#include
+
+TEST_CASE( "sleep_for_100ms", "[.min_duration_test][approvals]" )
+{
+ std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
+ CHECK( true );
+}
+
+TEST_CASE( "sleep_for_200ms", "[.min_duration_test][approvals]" )
+{
+ std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) );
+ CHECK( true );
+}
diff --git a/projects/TestScripts/testTimeThreshold.py b/projects/TestScripts/testTimeThreshold.py
new file mode 100644
index 0000000000..51804aaeb6
--- /dev/null
+++ b/projects/TestScripts/testTimeThreshold.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+
+import subprocess
+import sys
+
+def run_tests_with_threshold(self_test_exe, threshold):
+ cmd = [self_test_exe, '--min-duration', str(threshold),
+ '[min_duration_test]']
+ process = subprocess.Popen(
+ cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = process.communicate()
+ if stderr:
+ raise RuntimeError("Unexpected error output:\n" +
+ stderr.decode())
+ if process.returncode != 0:
+ raise RuntimeError("Unexpected failure to run tests\n")
+ result = stdout.split(b'\n')
+ report_lines = [s.split() for s in result if b' s: ' in s]
+ tests_reported = [l[2] for l in report_lines]
+ times_reported = [float(l[0]) for l in report_lines]
+ return tests_reported, times_reported
+
+def check_times_at_least(times_reported, minimum):
+ for time in times_reported:
+ assert time >= minimum, (
+ 'Time {} was less that requested minimum {}' .format(
+ time, minimum))
+
+def main():
+ self_test_exe, = sys.argv[1:]
+ tests, times = run_tests_with_threshold(self_test_exe, '0.15')
+ assert tests == [b'sleep_for_200ms'], (
+ "Unexpected tests reported %s" % tests)
+ check_times_at_least(times, 0.15)
+ tests,times = run_tests_with_threshold(self_test_exe, '0')
+ assert tests == [b'sleep_for_100ms', b'sleep_for_200ms'], (
+ "Unexpected tests reported %s" % tests)
+ check_times_at_least(times, 0)
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/single_include/catch2/catch.hpp b/single_include/catch2/catch.hpp
index 5ebd1a2d2a..909b5d663d 100644
--- a/single_include/catch2/catch.hpp
+++ b/single_include/catch2/catch.hpp
@@ -4522,6 +4522,7 @@ namespace Catch {
virtual int abortAfter() const = 0;
virtual bool showInvisibles() const = 0;
virtual ShowDurations::OrNot showDurations() const = 0;
+ virtual double minDuration() const = 0;
virtual TestSpec const& testSpec() const = 0;
virtual bool hasTestFilters() const = 0;
virtual std::vector const& getTestsOrTags() const = 0;