Commit 8b727aa7 by Abseil Team Committed by Xiaoyi Zhang

Changes imported from Abseil "staging" branch:

  - 5d8235b05f4ea2b33a138712f463a30b6ae75719 Incorporate PR https://github.com/abseil/abseil-cpp/pull/... by Xiaoyi Zhang <zhangxy@google.com>
  - f2bc653acdaa983aa2765693476c17cd1142d59b Run the StrSplit WorksWithLargeStrings test in all configs. by Matt Armstrong <marmstrong@google.com>
  - 43aed1ea7dffcd656e1916c2d5637650fc3a8de3 Incorporate PR https://github.com/abseil/abseil-cpp/pull/... by Xiaoyi Zhang <zhangxy@google.com>
  - d58511d60904c7090e44638339ba63b97ca96f1a Add a new simple Mutex lifetime test, to be extended later. by Greg Falcon <gfalcon@google.com>
  - db5c86c186c09ad57963bcbd2b6182f62bce8ed0 Actually use the exception in TestCheckerAtCountdown by Jon Cohen <cohenjon@google.com>
  - 29c01a72b62d9a4b90f9bd935e3575adbafd85ed Use factories instead of explicitly passing pointers to T... by Jon Cohen <cohenjon@google.com>
  - 54d5526ee6ab7784992845f6e6e2c7d48ba008a5 Fix uint128 ostream operator and improve ostream test. by Alex Strelnikov <strel@google.com>
  - 4e49abe7e569cf6bd0eae95ce2b2fe2faa051fa2 Fix documentation: strings::PairFormatter -> absl::PairFo... by Derek Mauro <dmauro@google.com>
  - 4044297f0e1a8a6c6ae3f781a65080e0d57c6751 Cut the memory used by the StrSplit WorksWithLargeStrings... by Jorg Brown <jorg@google.com>

GitOrigin-RevId: 5d8235b05f4ea2b33a138712f463a30b6ae75719
Change-Id: Ib6b6b0161c26e5326b53a126454754e33678eefc
parent 579f2879
...@@ -241,6 +241,7 @@ cc_library( ...@@ -241,6 +241,7 @@ cc_library(
"//absl/memory", "//absl/memory",
"//absl/meta:type_traits", "//absl/meta:type_traits",
"//absl/strings", "//absl/strings",
"//absl/types:optional",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
], ],
) )
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "absl/meta/type_traits.h" #include "absl/meta/type_traits.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/strings/substitute.h" #include "absl/strings/substitute.h"
#include "absl/types/optional.h"
namespace absl { namespace absl {
struct AllocInspector; struct AllocInspector;
...@@ -97,19 +98,50 @@ class TrackedObject { ...@@ -97,19 +98,50 @@ class TrackedObject {
friend struct ::absl::AllocInspector; friend struct ::absl::AllocInspector;
}; };
template <typename T, typename... Checkers> template <typename Factory>
testing::AssertionResult TestInvariants(const T& t, const TestException& e, using FactoryType = typename absl::result_of_t<Factory()>::element_type;
int count,
const Checkers&... checkers) { // Returns an optional with the result of the check if op fails, or an empty
auto out = AbslCheckInvariants(t); // optional if op passes
template <typename Factory, typename Op, typename Checker>
absl::optional<testing::AssertionResult> TestCheckerAtCountdown(
Factory factory, const Op& op, int count, const Checker& check) {
exceptions_internal::countdown = count;
auto t_ptr = factory();
absl::optional<testing::AssertionResult> out;
try {
op(t_ptr.get());
} catch (const exceptions_internal::TestException& e) {
out.emplace(check(t_ptr.get()));
if (!*out) {
*out << " caused by exception thrown by " << e.what();
}
}
return out;
}
template <typename Factory, typename Op, typename Checker>
int UpdateOut(Factory factory, const Op& op, int count, const Checker& checker,
testing::AssertionResult* out) {
if (*out) *out = *TestCheckerAtCountdown(factory, op, count, checker);
return 0;
}
// Returns an optional with the result of the check if op fails, or an empty
// optional if op passes
template <typename Factory, typename Op, typename... Checkers>
absl::optional<testing::AssertionResult> TestAtCountdown(
Factory factory, const Op& op, int count, const Checkers&... checkers) {
// Don't bother with the checkers if the class invariants are already broken. // Don't bother with the checkers if the class invariants are already broken.
bool dummy[] = {true, auto out = TestCheckerAtCountdown(
(out && (out = testing::AssertionResult(checkers(t))))...}; factory, op, count,
static_cast<void>(dummy); [](FactoryType<Factory>* t_ptr) { return AbslCheckInvariants(t_ptr); });
if (!out.has_value()) return out;
return out ? out // Run each checker, short circuiting after the first failure
: out << " Caused by exception " << count << "thrown by " int dummy[] = {0, (UpdateOut(factory, op, count, checkers, &*out))...};
<< e.what(); static_cast<void>(dummy);
return out;
} }
template <typename T, typename EqualTo> template <typename T, typename EqualTo>
...@@ -118,9 +150,9 @@ class StrongGuaranteeTester { ...@@ -118,9 +150,9 @@ class StrongGuaranteeTester {
explicit StrongGuaranteeTester(std::unique_ptr<T> t_ptr, EqualTo eq) noexcept explicit StrongGuaranteeTester(std::unique_ptr<T> t_ptr, EqualTo eq) noexcept
: val_(std::move(t_ptr)), eq_(eq) {} : val_(std::move(t_ptr)), eq_(eq) {}
testing::AssertionResult operator()(const T& other) const { testing::AssertionResult operator()(T* other) const {
return eq_(*val_, other) ? testing::AssertionSuccess() return eq_(*val_, *other) ? testing::AssertionSuccess()
: testing::AssertionFailure() << "State changed"; : testing::AssertionFailure() << "State changed";
} }
private: private:
...@@ -673,58 +705,52 @@ T TestThrowingCtor(Args&&... args) { ...@@ -673,58 +705,52 @@ T TestThrowingCtor(Args&&... args) {
} }
// Tests that performing operation Op on a T follows exception safety // Tests that performing operation Op on a T follows exception safety
// guarantees. By default only tests the basic guarantee. // guarantees. By default only tests the basic guarantee. There must be a
// function, AbslCheckInvariants(T*) which returns
// anything convertible to bool and which makes sure the invariants of the type
// are upheld. This is called before any of the checkers.
// //
// Parameters: // Parameters:
// * T: the type under test. // * TFactory: operator() returns a unique_ptr to the type under test (T). It
// should always return pointers to values which compare equal.
// * FunctionFromTPtrToVoid: A functor exercising the function under test. It // * FunctionFromTPtrToVoid: A functor exercising the function under test. It
// should take a T* and return void. // should take a T* and return void.
// * Checkers: Any number of functions taking a const T& and returning // * Checkers: Any number of functions taking a T* and returning
// anything contextually convertible to bool. If a testing::AssertionResult // anything contextually convertible to bool. If a testing::AssertionResult
// is used then the error message is kept. These test invariants related to // is used then the error message is kept. These test invariants related to
// the operation. To test the strong guarantee, pass // the operation. To test the strong guarantee, pass
// absl::StrongGuarantee(...) as one of these arguments if T has operator==. // absl::StrongGuarantee(factory). A checker may freely modify the passed-in
// Some types for which the strong guarantee makes sense don't have operator== // T, for example to make sure the T can be set to a known state.
// (eg std::any). A function capturing *t or a T equal to it, taking a const template <typename TFactory, typename FunctionFromTPtrToVoid,
// T&, and returning contextually-convertible-to-bool may be passed instead. typename... Checkers>
template <typename T, typename FunctionFromTPtrToVoid, typename... Checkers> testing::AssertionResult TestExceptionSafety(TFactory factory,
testing::AssertionResult TestExceptionSafety(T* t, FunctionFromTPtrToVoid&& op, FunctionFromTPtrToVoid&& op,
const Checkers&... checkers) { const Checkers&... checkers) {
auto out = testing::AssertionSuccess();
for (int countdown = 0;; ++countdown) { for (int countdown = 0;; ++countdown) {
exceptions_internal::countdown = countdown; auto out = exceptions_internal::TestAtCountdown(factory, op, countdown,
try { checkers...);
op(t); if (!out.has_value()) {
break; UnsetCountdown();
} catch (const exceptions_internal::TestException& e) { return testing::AssertionSuccess();
out = exceptions_internal::TestInvariants(*t, e, countdown, checkers...);
if (!out) return out;
} }
if (!*out) return *out;
} }
UnsetCountdown();
return out;
} }
// Returns a functor to test for the strong exception-safety guarantee. If T is // Returns a functor to test for the strong exception-safety guarantee.
// copyable, use the const T& overload, otherwise pass a unique_ptr<T>. // Equality comparisons are made against the T provided by the factory and
// Equality comparisons are made against the T provided and default to using // default to using operator==.
// operator==. See the documentation for TestExceptionSafety if T doesn't have
// operator== but the strong guarantee still makes sense for it.
// //
// Parameters: // Parameters:
// * T: The type under test. // * TFactory: operator() returns a unique_ptr to the type under test. It
template <typename T, typename EqualTo = std::equal_to<T>> // should always return pointers to values which compare equal.
exceptions_internal::StrongGuaranteeTester<T, EqualTo> StrongGuarantee( template <typename TFactory, typename EqualTo = std::equal_to<
const T& t, EqualTo eq = EqualTo()) { exceptions_internal::FactoryType<TFactory>>>
return exceptions_internal::StrongGuaranteeTester<T, EqualTo>( exceptions_internal::StrongGuaranteeTester<
absl::make_unique<T>(t), eq); exceptions_internal::FactoryType<TFactory>, EqualTo>
} StrongGuarantee(TFactory factory, EqualTo eq = EqualTo()) {
return exceptions_internal::StrongGuaranteeTester<
template <typename T, typename EqualTo = std::equal_to<T>> exceptions_internal::FactoryType<TFactory>, EqualTo>(factory(), eq);
exceptions_internal::StrongGuaranteeTester<T, EqualTo> PointeeStrongGuarantee(
std::unique_ptr<T> t_ptr, EqualTo eq = EqualTo()) {
return exceptions_internal::StrongGuaranteeTester<T, EqualTo>(
std::move(t_ptr), eq);
} }
} // namespace absl } // namespace absl
......
...@@ -28,6 +28,7 @@ cc_test( ...@@ -28,6 +28,7 @@ cc_test(
size = "small", size = "small",
srcs = [ srcs = [
"int128_test.cc", "int128_test.cc",
"int128_test_unsigned_ostream_cases.inc",
], ],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
deps = [ deps = [
......
...@@ -192,9 +192,8 @@ std::ostream& operator<<(std::ostream& o, const uint128& b) { ...@@ -192,9 +192,8 @@ std::ostream& operator<<(std::ostream& o, const uint128& b) {
rep.append(width - rep.size(), o.fill()); rep.append(width - rep.size(), o.fill());
} else if (adjustfield == std::ios::internal && } else if (adjustfield == std::ios::internal &&
(flags & std::ios::showbase) && (flags & std::ios::showbase) &&
(flags & std::ios::basefield) != std::ios::dec) { (flags & std::ios::basefield) == std::ios::hex && b != 0) {
size_t base_size = (flags & std::ios::basefield) == std::ios::hex ? 2 : 1; rep.insert(2, width - rep.size(), o.fill());
rep.insert(base_size, width - rep.size(), o.fill());
} else { } else {
rep.insert(0, width - rep.size(), o.fill()); rep.insert(0, width - rep.size(), o.fill());
} }
......
...@@ -428,79 +428,18 @@ TEST(Uint128, ConstexprTest) { ...@@ -428,79 +428,18 @@ TEST(Uint128, ConstexprTest) {
} }
TEST(Uint128, OStream) { TEST(Uint128, OStream) {
struct { struct StreamCase {
absl::uint128 val; absl::uint128 val;
std::ios_base::fmtflags flags; std::ios_base::fmtflags flags;
std::streamsize width; std::streamsize width;
char fill; char fill;
const char* rep; const char* rep;
} cases[] = {
// zero with different bases
{absl::uint128(0), std::ios::dec, 0, '_', "0"},
{absl::uint128(0), std::ios::oct, 0, '_', "0"},
{absl::uint128(0), std::ios::hex, 0, '_', "0"},
// crossover between lo_ and hi_
{absl::MakeUint128(0, -1), std::ios::dec, 0, '_', "18446744073709551615"},
{absl::MakeUint128(0, -1), std::ios::oct, 0, '_',
"1777777777777777777777"},
{absl::MakeUint128(0, -1), std::ios::hex, 0, '_', "ffffffffffffffff"},
{absl::MakeUint128(1, 0), std::ios::dec, 0, '_', "18446744073709551616"},
{absl::MakeUint128(1, 0), std::ios::oct, 0, '_',
"2000000000000000000000"},
{absl::MakeUint128(1, 0), std::ios::hex, 0, '_', "10000000000000000"},
// just the top bit
{absl::MakeUint128(0x8000000000000000, 0), std::ios::dec, 0, '_',
"170141183460469231731687303715884105728"},
{absl::MakeUint128(0x8000000000000000, 0), std::ios::oct, 0, '_',
"2000000000000000000000000000000000000000000"},
{absl::MakeUint128(0x8000000000000000, 0), std::ios::hex, 0, '_',
"80000000000000000000000000000000"},
// maximum absl::uint128 value
{absl::MakeUint128(-1, -1), std::ios::dec, 0, '_',
"340282366920938463463374607431768211455"},
{absl::MakeUint128(-1, -1), std::ios::oct, 0, '_',
"3777777777777777777777777777777777777777777"},
{absl::MakeUint128(-1, -1), std::ios::hex, 0, '_',
"ffffffffffffffffffffffffffffffff"},
// uppercase
{absl::MakeUint128(-1, -1), std::ios::hex | std::ios::uppercase, 0, '_',
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"},
// showbase
{absl::uint128(1), std::ios::dec | std::ios::showbase, 0, '_', "1"},
{absl::uint128(1), std::ios::oct | std::ios::showbase, 0, '_', "01"},
{absl::uint128(1), std::ios::hex | std::ios::showbase, 0, '_', "0x1"},
// showbase does nothing on zero
{absl::uint128(0), std::ios::dec | std::ios::showbase, 0, '_', "0"},
{absl::uint128(0), std::ios::oct | std::ios::showbase, 0, '_', "0"},
{absl::uint128(0), std::ios::hex | std::ios::showbase, 0, '_', "0"},
// showpos does nothing on unsigned types
{absl::uint128(1), std::ios::dec | std::ios::showpos, 0, '_', "1"},
// right adjustment
{absl::uint128(9), std::ios::dec, 6, '_', "_____9"},
{absl::uint128(12345), std::ios::dec, 6, '_', "_12345"},
{absl::uint128(31), std::ios::hex | std::ios::showbase, 6, '_', "__0x1f"},
{absl::uint128(7), std::ios::oct | std::ios::showbase, 6, '_', "____07"},
// left adjustment
{absl::uint128(9), std::ios::dec | std::ios::left, 6, '_', "9_____"},
{absl::uint128(12345), std::ios::dec | std::ios::left, 6, '_', "12345_"},
{absl::uint128(31), std::ios::hex | std::ios::left | std::ios::showbase,
6, '_', "0x1f__"},
{absl::uint128(7), std::ios::oct | std::ios::left | std::ios::showbase, 6,
'_', "07____"},
// internal adjustment
{absl::uint128(123),
std::ios::dec | std::ios::internal | std::ios::showbase, 6, '_',
"___123"},
{absl::uint128(31),
std::ios::hex | std::ios::internal | std::ios::showbase, 6, '_',
"0x__1f"},
{absl::uint128(7),
std::ios::oct | std::ios::internal | std::ios::showbase, 6, '_',
"0____7"},
{absl::uint128(34), std::ios::hex | std::ios::internal, 6, '_', "____22"},
{absl::uint128(9), std::ios::oct | std::ios::internal, 6, '_', "____11"},
}; };
for (const auto& test_case : cases) {
std::vector<StreamCase> cases = {
#include "absl/numeric/int128_test_unsigned_ostream_cases.inc"
};
for (const StreamCase& test_case : cases) {
std::ostringstream os; std::ostringstream os;
os.flags(test_case.flags); os.flags(test_case.flags);
os.width(test_case.width); os.width(test_case.width);
......
...@@ -208,11 +208,11 @@ DereferenceFormatter() { ...@@ -208,11 +208,11 @@ DereferenceFormatter() {
// // Joins a `std::map`, with each key-value pair separated by an equals // // Joins a `std::map`, with each key-value pair separated by an equals
// // sign. This pattern would also work with, say, a // // sign. This pattern would also work with, say, a
// // `std::vector<std::pair<>>`. // // `std::vector<std::pair<>>`.
// std::map<std::string, int> m = { // std::map<std::string, int> m = {
// std::make_pair("a", 1), // std::make_pair("a", 1),
// std::make_pair("b", 2), // std::make_pair("b", 2),
// std::make_pair("c", 3)}; // std::make_pair("c", 3)};
// std::string s = absl::StrJoin(m, ",", strings::PairFormatter("=")); // std::string s = absl::StrJoin(m, ",", absl::PairFormatter("="));
// EXPECT_EQ("a=1,b=2,c=3", s); // EXPECT_EQ("a=1,b=2,c=3", s);
// //
// Example 7: // Example 7:
......
...@@ -857,12 +857,10 @@ TEST(Delimiter, ByLength) { ...@@ -857,12 +857,10 @@ TEST(Delimiter, ByLength) {
EXPECT_FALSE(IsFoundAt("abcd", four_char_delim, 0)); EXPECT_FALSE(IsFoundAt("abcd", four_char_delim, 0));
} }
// Allocates too much memory for TSan and MSan.
#if !defined(THREAD_SANITIZER) && !defined(MEMORY_SANITIZER)
TEST(Split, WorksWithLargeStrings) { TEST(Split, WorksWithLargeStrings) {
if (sizeof(size_t) > 4 && !RunningOnValgrind()) { if (sizeof(size_t) > 4) {
std::string s(1ULL << 31, 'x'); std::string s((uint32_t{1} << 31) + 1, 'x'); // 2G + 1 byte
s.push_back('-'); // 2G + 1 byte s.back() = '-';
std::vector<absl::string_view> v = absl::StrSplit(s, '-'); std::vector<absl::string_view> v = absl::StrSplit(s, '-');
EXPECT_EQ(2, v.size()); EXPECT_EQ(2, v.size());
// The first element will contain 2G of 'x's. // The first element will contain 2G of 'x's.
...@@ -873,7 +871,6 @@ TEST(Split, WorksWithLargeStrings) { ...@@ -873,7 +871,6 @@ TEST(Split, WorksWithLargeStrings) {
EXPECT_EQ("", v[1]); EXPECT_EQ("", v[1]);
} }
} }
#endif // THREAD_SANITIZER
TEST(SplitInternalTest, TypeTraits) { TEST(SplitInternalTest, TypeTraits) {
EXPECT_FALSE(absl::strings_internal::HasMappedType<int>::value); EXPECT_FALSE(absl::strings_internal::HasMappedType<int>::value);
......
...@@ -190,3 +190,19 @@ cc_test( ...@@ -190,3 +190,19 @@ cc_test(
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )
cc_test(
name = "lifetime_test",
srcs = [
"lifetime_test.cc",
],
copts = ABSL_TEST_COPTS,
linkopts = select({
"//absl:windows": [],
"//conditions:default": ["-pthread"],
}),
deps = [
":synchronization",
"//absl/base",
],
)
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdlib>
#include <thread> // NOLINT(build/c++11), Abseil test
#include <type_traits>
#include "absl/base/attributes.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/synchronization/mutex.h"
#include "absl/synchronization/notification.h"
namespace {
// A two-threaded test which checks that Mutex, CondVar, and Notification have
// correct basic functionality. The intent is to establish that they
// function correctly in various phases of construction and destruction.
//
// Thread one acquires a lock on 'mutex', wakes thread two via 'notification',
// then waits for 'state' to be set, as signalled by 'condvar'.
//
// Thread two waits on 'notification', then sets 'state' inside the 'mutex',
// signalling the change via 'condvar'.
//
// These tests use ABSL_RAW_CHECK to validate invariants, rather than EXPECT or
// ASSERT from gUnit, because we need to invoke them during global destructors,
// when gUnit teardown would have already begun.
void ThreadOne(absl::Mutex* mutex, absl::CondVar* condvar,
absl::Notification* notification, bool* state) {
// Test that the notification is in a valid initial state.
ABSL_RAW_CHECK(!notification->HasBeenNotified(), "invalid Notification");
ABSL_RAW_CHECK(*state == false, "*state not initialized");
{
absl::MutexLock lock(mutex);
notification->Notify();
ABSL_RAW_CHECK(notification->HasBeenNotified(), "invalid Notification");
while (*state == false) {
condvar->Wait(mutex);
}
}
}
void ThreadTwo(absl::Mutex* mutex, absl::CondVar* condvar,
absl::Notification* notification, bool* state) {
ABSL_RAW_CHECK(*state == false, "*state not initialized");
// Wake thread one
notification->WaitForNotification();
ABSL_RAW_CHECK(notification->HasBeenNotified(), "invalid Notification");
{
absl::MutexLock lock(mutex);
*state = true;
condvar->Signal();
}
}
// Launch thread 1 and thread 2, and block on their completion.
void RunTests(absl::Mutex* mutex, absl::CondVar* condvar,
absl::Notification* notification) {
bool state = false;
std::thread thread_one(ThreadOne, mutex, condvar, notification, &state);
std::thread thread_two(ThreadTwo, mutex, condvar, notification, &state);
thread_one.join();
thread_two.join();
}
void TestLocals() {
absl::Mutex mutex;
absl::CondVar condvar;
absl::Notification notification;
RunTests(&mutex, &condvar, &notification);
}
} // namespace
int main() {
TestLocals();
// Explicitly call exit(0) here, to make it clear that we intend for the
// above global object destructors to run.
std::exit(0);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment