Skip to content

Commit 8883b42

Browse files
author
vladlosev
committed
Implements the timestamp attribute for the testsuites element in the output XML (external contribution by Dirk Meister).
git-svn-id: http://googletest.googlecode.com/svn/trunk@600 861a406c-534a-0410-8894-cb66d6ee9925
1 parent e350196 commit 8883b42

File tree

7 files changed

+243
-41
lines changed

7 files changed

+243
-41
lines changed

include/gtest/gtest.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,10 @@ class GTEST_API_ UnitTest {
11521152
// Gets the number of tests that should run.
11531153
int test_to_run_count() const;
11541154

1155+
// Gets the time of the test program start, in ms from the start of the
1156+
// UNIX epoch.
1157+
TimeInMillis start_timestamp() const;
1158+
11551159
// Gets the elapsed time, in milliseconds.
11561160
TimeInMillis elapsed_time() const;
11571161

src/gtest-internal-inl.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
112112
// Formats the given time in milliseconds as seconds.
113113
GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms);
114114

115+
// Converts the given time in milliseconds to a date string in the ISO 8601
116+
// format, without the timezone information. N.B.: due to the use the
117+
// non-reentrant localtime() function, this function is not thread safe. Do
118+
// not use it in any code that can be called from multiple threads.
119+
GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms);
120+
115121
// Parses a string for an Int32 flag, in the form of "--flag=value".
116122
//
117123
// On success, stores the value of the flag in *value, and returns
@@ -548,6 +554,10 @@ class GTEST_API_ UnitTestImpl {
548554
// Gets the number of tests that should run.
549555
int test_to_run_count() const;
550556

557+
// Gets the time of the test program start, in ms from the start of the
558+
// UNIX epoch.
559+
TimeInMillis start_timestamp() const { return start_timestamp_; }
560+
551561
// Gets the elapsed time, in milliseconds.
552562
TimeInMillis elapsed_time() const { return elapsed_time_; }
553563

@@ -880,6 +890,10 @@ class GTEST_API_ UnitTestImpl {
880890
// Our random number generator.
881891
internal::Random random_;
882892

893+
// The time of the test program start, in ms from the start of the
894+
// UNIX epoch.
895+
TimeInMillis start_timestamp_;
896+
883897
// How long the test took to run, in milliseconds.
884898
TimeInMillis elapsed_time_;
885899

src/gtest.cc

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <stdarg.h>
4040
#include <stdio.h>
4141
#include <stdlib.h>
42+
#include <time.h>
4243
#include <wchar.h>
4344
#include <wctype.h>
4445

@@ -3195,6 +3196,32 @@ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) {
31953196
return ss.str();
31963197
}
31973198

3199+
// Converts the given epoch time in milliseconds to a date string in the ISO
3200+
// 8601 format, without the timezone information.
3201+
std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) {
3202+
// Using non-reentrant version as localtime_r is not portable.
3203+
time_t seconds = static_cast<time_t>(ms / 1000);
3204+
#ifdef _MSC_VER
3205+
# pragma warning(push) // Saves the current warning state.
3206+
# pragma warning(disable:4996) // Temporarily disables warning 4996
3207+
// (function or variable may be unsafe).
3208+
const struct tm* const time_struct = localtime(&seconds); // NOLINT
3209+
# pragma warning(pop) // Restores the warning state again.
3210+
#else
3211+
const struct tm* const time_struct = localtime(&seconds); // NOLINT
3212+
#endif
3213+
if (time_struct == NULL)
3214+
return ""; // Invalid ms value
3215+
3216+
return String::Format("%d-%02d-%02dT%02d:%02d:%02d", // YYYY-MM-DDThh:mm:ss
3217+
time_struct->tm_year + 1900,
3218+
time_struct->tm_mon + 1,
3219+
time_struct->tm_mday,
3220+
time_struct->tm_hour,
3221+
time_struct->tm_min,
3222+
time_struct->tm_sec);
3223+
}
3224+
31983225
// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
31993226
void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
32003227
const char* data) {
@@ -3291,10 +3318,11 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,
32913318
fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
32923319
fprintf(out,
32933320
"<testsuites tests=\"%d\" failures=\"%d\" disabled=\"%d\" "
3294-
"errors=\"0\" time=\"%s\" ",
3321+
"errors=\"0\" timestamp=\"%s\" time=\"%s\" ",
32953322
unit_test.total_test_count(),
32963323
unit_test.failed_test_count(),
32973324
unit_test.disabled_test_count(),
3325+
FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp()).c_str(),
32983326
FormatTimeInMillisAsSeconds(unit_test.elapsed_time()).c_str());
32993327
if (GTEST_FLAG(shuffle)) {
33003328
fprintf(out, "random_seed=\"%d\" ", unit_test.random_seed());
@@ -3687,6 +3715,12 @@ int UnitTest::total_test_count() const { return impl()->total_test_count(); }
36873715
// Gets the number of tests that should run.
36883716
int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); }
36893717

3718+
// Gets the time of the test program start, in ms from the start of the
3719+
// UNIX epoch.
3720+
internal::TimeInMillis UnitTest::start_timestamp() const {
3721+
return impl()->start_timestamp();
3722+
}
3723+
36903724
// Gets the elapsed time, in milliseconds.
36913725
internal::TimeInMillis UnitTest::elapsed_time() const {
36923726
return impl()->elapsed_time();
@@ -3961,6 +3995,7 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent)
39613995
post_flag_parse_init_performed_(false),
39623996
random_seed_(0), // Will be overridden by the flag before first use.
39633997
random_(0), // Will be reseeded before first use.
3998+
start_timestamp_(0),
39643999
elapsed_time_(0),
39654000
#if GTEST_HAS_DEATH_TEST
39664001
internal_run_death_test_flag_(NULL),
@@ -4192,6 +4227,7 @@ bool UnitTestImpl::RunAllTests() {
41924227

41934228
TestEventListener* repeater = listeners()->repeater();
41944229

4230+
start_timestamp_ = GetTimeInMillis();
41954231
repeater->OnTestProgramStart(*parent_);
41964232

41974233
// How many times to repeat the tests? We don't want to repeat them

test/gtest_unittest.cc

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded) {
7171

7272
#include <limits.h> // For INT_MAX.
7373
#include <stdlib.h>
74+
#include <string.h>
7475
#include <time.h>
7576

7677
#include <map>
@@ -141,6 +142,7 @@ using testing::TestPartResult;
141142
using testing::TestPartResultArray;
142143
using testing::TestProperty;
143144
using testing::TestResult;
145+
using testing::TimeInMillis;
144146
using testing::UnitTest;
145147
using testing::kMaxStackTraceDepth;
146148
using testing::internal::AddReference;
@@ -156,13 +158,15 @@ using testing::internal::CountIf;
156158
using testing::internal::EqFailure;
157159
using testing::internal::FloatingPoint;
158160
using testing::internal::ForEach;
161+
using testing::internal::FormatEpochTimeInMillisAsIso8601;
159162
using testing::internal::FormatTimeInMillisAsSeconds;
160163
using testing::internal::GTestFlagSaver;
161164
using testing::internal::GetCurrentOsStackTraceExceptTop;
162165
using testing::internal::GetElementOr;
163166
using testing::internal::GetNextRandomSeed;
164167
using testing::internal::GetRandomSeedFromFlag;
165168
using testing::internal::GetTestTypeId;
169+
using testing::internal::GetTimeInMillis;
166170
using testing::internal::GetTypeId;
167171
using testing::internal::GetUnitTestImpl;
168172
using testing::internal::ImplicitlyConvertible;
@@ -308,6 +312,103 @@ TEST(FormatTimeInMillisAsSecondsTest, FormatsNegativeNumber) {
308312
EXPECT_EQ("-3", FormatTimeInMillisAsSeconds(-3000));
309313
}
310314

315+
// Tests FormatEpochTimeInMillisAsIso8601(). The correctness of conversion
316+
// for particular dates below was verified in Python using
317+
// datetime.datetime.fromutctimestamp(<timetamp>/1000).
318+
319+
// FormatEpochTimeInMillisAsIso8601 depends on the current timezone, so we
320+
// have to set up a particular timezone to obtain predictable results.
321+
class FormatEpochTimeInMillisAsIso8601Test : public Test {
322+
public:
323+
// On Cygwin, GCC doesn't allow unqualified integer literals to exceed
324+
// 32 bits, even when 64-bit integer types are available. We have to
325+
// force the constants to have a 64-bit type here.
326+
static const TimeInMillis kMillisPerSec = 1000;
327+
328+
private:
329+
virtual void SetUp() {
330+
saved_tz_ = NULL;
331+
#if _MSC_VER
332+
# pragma warning(push) // Saves the current warning state.
333+
# pragma warning(disable:4996) // Temporarily disables warning 4996
334+
// (function or variable may be unsafe
335+
// for getenv, function is deprecated for
336+
// strdup).
337+
if (getenv("TZ"))
338+
saved_tz_ = strdup(getenv("TZ"));
339+
# pragma warning(pop) // Restores the warning state again.
340+
#else
341+
if (getenv("TZ"))
342+
saved_tz_ = strdup(getenv("TZ"));
343+
#endif
344+
345+
// Set up the time zone for FormatEpochTimeInMillisAsIso8601 to use. We
346+
// cannot use the local time zone because the function's output depends
347+
// on the time zone.
348+
SetTimeZone("UTC+00");
349+
}
350+
351+
virtual void TearDown() {
352+
SetTimeZone(saved_tz_);
353+
free(const_cast<char*>(saved_tz_));
354+
saved_tz_ = NULL;
355+
}
356+
357+
static void SetTimeZone(const char* time_zone) {
358+
// tzset() distinguishes between the TZ variable being present and empty
359+
// and not being present, so we have to consider the case of time_zone
360+
// being NULL.
361+
#if _MSC_VER
362+
// ...Unless it's MSVC, whose standard library's _putenv doesn't
363+
// distinguish between an empty and a missing variable.
364+
const std::string env_var =
365+
std::string("TZ=") + (time_zone ? time_zone : "");
366+
_putenv(env_var.c_str());
367+
# pragma warning(push) // Saves the current warning state.
368+
# pragma warning(disable:4996) // Temporarily disables warning 4996
369+
// (function is deprecated).
370+
tzset();
371+
# pragma warning(pop) // Restores the warning state again.
372+
#else
373+
if (time_zone) {
374+
setenv(("TZ"), time_zone, 1);
375+
} else {
376+
unsetenv("TZ");
377+
}
378+
tzset();
379+
#endif
380+
}
381+
382+
const char* saved_tz_;
383+
};
384+
385+
const TimeInMillis FormatEpochTimeInMillisAsIso8601Test::kMillisPerSec;
386+
387+
TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsTwoDigitSegments) {
388+
EXPECT_EQ("2011-10-31T18:52:42",
389+
FormatEpochTimeInMillisAsIso8601(1320087162 * kMillisPerSec));
390+
}
391+
392+
TEST_F(FormatEpochTimeInMillisAsIso8601Test, MillisecondsDoNotAffectResult) {
393+
EXPECT_EQ(
394+
"2011-10-31T18:52:42",
395+
FormatEpochTimeInMillisAsIso8601(1320087162 * kMillisPerSec + 234));
396+
}
397+
398+
TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsLeadingZeroes) {
399+
EXPECT_EQ("2011-09-03T05:07:02",
400+
FormatEpochTimeInMillisAsIso8601(1315026422 * kMillisPerSec));
401+
}
402+
403+
TEST_F(FormatEpochTimeInMillisAsIso8601Test, Prints24HourTime) {
404+
EXPECT_EQ("2011-09-28T17:08:22",
405+
FormatEpochTimeInMillisAsIso8601(1317229702 * kMillisPerSec));
406+
}
407+
408+
TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsEpochStart) {
409+
EXPECT_EQ("1970-01-01T00:00:00", FormatEpochTimeInMillisAsIso8601(0));
410+
}
411+
311412
#if GTEST_CAN_COMPARE_NULL
312413

313414
# ifdef __BORLANDC__
@@ -2130,6 +2231,11 @@ TEST(UnitTestTest, CanGetOriginalWorkingDir) {
21302231
EXPECT_STRNE(UnitTest::GetInstance()->original_working_dir(), "");
21312232
}
21322233

2234+
TEST(UnitTestTest, ReturnsPlausibleTimestamp) {
2235+
EXPECT_LT(0, UnitTest::GetInstance()->start_timestamp());
2236+
EXPECT_LE(UnitTest::GetInstance()->start_timestamp(), GetTimeInMillis());
2237+
}
2238+
21332239
// This group of tests is for predicate assertions (ASSERT_PRED*, etc)
21342240
// of various arities. They do not attempt to be exhaustive. Rather,
21352241
// view them as smoke tests that can be easily reviewed and verified.

test/gtest_xml_outfiles_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,15 @@
4545
GTEST_OUTPUT_2_TEST = "gtest_xml_outfile2_test_"
4646

4747
EXPECTED_XML_1 = """<?xml version="1.0" encoding="UTF-8"?>
48-
<testsuites tests="1" failures="0" disabled="0" errors="0" time="*" name="AllTests">
48+
<testsuites tests="1" failures="0" disabled="0" errors="0" time="*" timestamp="*" name="AllTests">
4949
<testsuite name="PropertyOne" tests="1" failures="0" disabled="0" errors="0" time="*">
5050
<testcase name="TestSomeProperties" status="run" time="*" classname="PropertyOne" SetUpProp="1" TestSomeProperty="1" TearDownProp="1" />
5151
</testsuite>
5252
</testsuites>
5353
"""
5454

5555
EXPECTED_XML_2 = """<?xml version="1.0" encoding="UTF-8"?>
56-
<testsuites tests="1" failures="0" disabled="0" errors="0" time="*" name="AllTests">
56+
<testsuites tests="1" failures="0" disabled="0" errors="0" time="*" timestamp="*" name="AllTests">
5757
<testsuite name="PropertyTwo" tests="1" failures="0" disabled="0" errors="0" time="*">
5858
<testcase name="TestSomeProperties" status="run" time="*" classname="PropertyTwo" SetUpProp="2" TestSomeProperty="2" TearDownProp="2" />
5959
</testsuite>

0 commit comments

Comments
 (0)