aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2009-09-21 19:42:03 +0000
committerzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2009-09-21 19:42:03 +0000
commit2534ae201e47986d36d5fab0e523a7f046b8ec1e (patch)
tree70aacac236ddc0e5c5941b7c92970f9b3c743d57
parente5373af0cb9cae249e7bc618cae3483397332895 (diff)
downloadgoogletest-2534ae201e47986d36d5fab0e523a7f046b8ec1e.tar.gz
googletest-2534ae201e47986d36d5fab0e523a7f046b8ec1e.tar.bz2
googletest-2534ae201e47986d36d5fab0e523a7f046b8ec1e.zip
Adds a Random class to support --gtest_shuffle (by Josh Kelley); Makes the scons script build in a deterministic order (by Zhanyong Wan).
-rw-r--r--include/gtest/internal/gtest-internal.h22
-rw-r--r--scons/SConstruct.common5
-rw-r--r--src/gtest.cc21
-rw-r--r--test/gtest_unittest.cc44
4 files changed, 86 insertions, 6 deletions
diff --git a/include/gtest/internal/gtest-internal.h b/include/gtest/internal/gtest-internal.h
index 47755243..f5c30fb5 100644
--- a/include/gtest/internal/gtest-internal.h
+++ b/include/gtest/internal/gtest-internal.h
@@ -748,6 +748,28 @@ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count);
// A helper for suppressing warnings on unreachable code in some macros.
bool AlwaysTrue();
+// A simple Linear Congruential Generator for generating random
+// numbers with a uniform distribution. Unlike rand() and srand(), it
+// doesn't use global state (and therefore can't interfere with user
+// code). Unlike rand_r(), it's portable. An LCG isn't very random,
+// but it's good enough for our purposes.
+class Random {
+ public:
+ static const UInt32 kMaxRange = 1u << 31;
+
+ explicit Random(UInt32 seed) : state_(seed) {}
+
+ void Reseed(UInt32 seed) { state_ = seed; }
+
+ // Generates a random number from [0, range). Crashes if 'range' is
+ // 0 or greater than kMaxRange.
+ UInt32 Generate(UInt32 range);
+
+ private:
+ UInt32 state_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Random);
+};
+
} // namespace internal
} // namespace testing
diff --git a/scons/SConstruct.common b/scons/SConstruct.common
index 193fab21..f849d727 100644
--- a/scons/SConstruct.common
+++ b/scons/SConstruct.common
@@ -155,11 +155,6 @@ class SConstructHelper:
'/OPT:NOICF',
]
)
- # Tell SCons to build depdendencies in random order (apart from the
- # actual dependency order). This helps ensure we don't introduce
- # build files that "accidentally" work sometimes (e.g. when you are
- # building some targets) and not other times.
- debug_env.SetOption('random', 1)
return debug_env
def MakeWinOptimizedEnvironment(self, base_environment, name):
diff --git a/src/gtest.cc b/src/gtest.cc
index bb5ffacc..30652fe1 100644
--- a/src/gtest.cc
+++ b/src/gtest.cc
@@ -260,6 +260,25 @@ GTEST_DEFINE_bool_(
namespace internal {
+// Generates a random number from [0, range), using a Linear
+// Congruential Generator (LCG). Crashes if 'range' is 0 or greater
+// than kMaxRange.
+UInt32 Random::Generate(UInt32 range) {
+ // These constants are the same as are used in glibc's rand(3).
+ state_ = (1103515245U*state_ + 12345U) % kMaxRange;
+
+ GTEST_CHECK_(range > 0)
+ << "Cannot generate a number in the range [0, 0).";
+ GTEST_CHECK_(range <= kMaxRange)
+ << "Generation of a number in [0, " << range << ") was requested, "
+ << "but this can only generate numbers in [0, " << kMaxRange << ").";
+
+ // Converting via modulus introduces a bit of downward bias, but
+ // it's simple, and a linear congruential generator isn't too good
+ // to begin with.
+ return state_ % range;
+}
+
// g_help_flag is true iff the --help flag or an equivalent form is
// specified on the command line.
static bool g_help_flag = false;
@@ -3815,7 +3834,7 @@ static void TearDownEnvironment(Environment* env) { env->TearDown(); }
// considered to be failed, but the rest of the tests will still be
// run. (We disable exceptions on Linux and Mac OS X, so the issue
// doesn't apply there.)
-// When parameterized tests are enabled, it explands and registers
+// When parameterized tests are enabled, it expands and registers
// parameterized tests first in RegisterParameterizedTests().
// All other functions called from RunAllTests() may safely assume that
// parameterized tests are ready to be counted and run.
diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc
index 3b1457d4..d5315c46 100644
--- a/test/gtest_unittest.cc
+++ b/test/gtest_unittest.cc
@@ -183,6 +183,7 @@ using testing::internal::TestProperty;
using testing::internal::TestResult;
using testing::internal::TestResultAccessor;
using testing::internal::ThreadLocal;
+using testing::internal::UInt32;
using testing::internal::Vector;
using testing::internal::WideStringToUtf8;
using testing::internal::kTestTypeIdInGoogleTest;
@@ -499,6 +500,49 @@ TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) {
}
#endif // !GTEST_WIDE_STRING_USES_UTF16_
+// Tests the Random class.
+
+TEST(RandomDeathTest, GeneratesCrashesOnInvalidRange) {
+ testing::internal::Random random(42);
+ EXPECT_DEATH_IF_SUPPORTED(
+ random.Generate(0),
+ "Cannot generate a number in the range \\[0, 0\\)");
+ EXPECT_DEATH_IF_SUPPORTED(
+ random.Generate(testing::internal::Random::kMaxRange + 1),
+ "Generation of a number in \\[0, 2147483649\\) was requested, "
+ "but this can only generate numbers in \\[0, 2147483648\\)");
+}
+
+TEST(RandomTest, GeneratesNumbersWithinRange) {
+ const UInt32 kRange = 10000;
+ testing::internal::Random random(12345);
+ for (int i = 0; i < 10; i++) {
+ EXPECT_LT(random.Generate(kRange), kRange) << " for iteration " << i;
+ }
+
+ testing::internal::Random random2(testing::internal::Random::kMaxRange);
+ for (int i = 0; i < 10; i++) {
+ EXPECT_LT(random2.Generate(kRange), kRange) << " for iteration " << i;
+ }
+}
+
+TEST(RandomTest, RepeatsWhenReseeded) {
+ const int kSeed = 123;
+ const int kArraySize = 10;
+ const UInt32 kRange = 10000;
+ UInt32 values[kArraySize];
+
+ testing::internal::Random random(kSeed);
+ for (int i = 0; i < kArraySize; i++) {
+ values[i] = random.Generate(kRange);
+ }
+
+ random.Reseed(kSeed);
+ for (int i = 0; i < kArraySize; i++) {
+ EXPECT_EQ(values[i], random.Generate(kRange)) << " for iteration " << i;
+ }
+}
+
// Tests the Vector class template.
// Tests Vector::Clear().