summaryrefslogtreecommitdiff
path: root/chromium/base/test
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-06 12:48:11 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:33:43 +0000
commit7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (patch)
treefa14ba0ca8d2683ba2efdabd246dc9b18a1229c6 /chromium/base/test
parent79b4f909db1049fca459c07cca55af56a9b54fe3 (diff)
downloadqtwebengine-chromium-7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3.tar.gz
BASELINE: Update Chromium to 84.0.4147.141
Change-Id: Ib85eb4cfa1cbe2b2b81e5022c8cad5c493969535 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/base/test')
-rw-r--r--chromium/base/test/BUILD.gn2
-rw-r--r--chromium/base/test/DEPS3
-rw-r--r--chromium/base/test/OWNERS15
-rw-r--r--chromium/base/test/bind_test_util.cc72
-rw-r--r--chromium/base/test/bind_test_util.h89
-rw-r--r--chromium/base/test/clang_profiling.cc26
-rw-r--r--chromium/base/test/clang_profiling.h28
-rw-r--r--chromium/base/test/copy_only_int.cc12
-rw-r--r--chromium/base/test/copy_only_int.h61
-rw-r--r--chromium/base/test/fontconfig_util_linux.cc2
-rw-r--r--chromium/base/test/generate_fontconfig_caches.cc66
-rw-r--r--chromium/base/test/gmock_callback_support.h150
-rw-r--r--chromium/base/test/gmock_callback_support_unittest.cc178
-rw-r--r--chromium/base/test/gmock_move_support.h20
-rw-r--r--chromium/base/test/gmock_move_support_unittest.cc60
-rw-r--r--chromium/base/test/gtest_util.cc111
-rw-r--r--chromium/base/test/gtest_util.h114
-rw-r--r--chromium/base/test/gtest_xml_unittest_result_printer.cc165
-rw-r--r--chromium/base/test/gtest_xml_unittest_result_printer.h55
-rw-r--r--chromium/base/test/gtest_xml_util.cc235
-rw-r--r--chromium/base/test/gtest_xml_util.h27
-rw-r--r--chromium/base/test/icu_test_util.cc49
-rw-r--r--chromium/base/test/icu_test_util.h59
-rw-r--r--chromium/base/test/immediate_crash_test_helper.cc32
-rw-r--r--chromium/base/test/malloc_wrapper.cc11
-rw-r--r--chromium/base/test/malloc_wrapper.h22
-rw-r--r--chromium/base/test/mock_callback.h386
-rw-r--r--chromium/base/test/mock_callback.h.pump104
-rw-r--r--chromium/base/test/mock_callback_unittest.cc81
-rw-r--r--chromium/base/test/mock_chrome_application_mac.mm49
-rw-r--r--chromium/base/test/mock_devices_changed_observer.cc13
-rw-r--r--chromium/base/test/mock_devices_changed_observer.h31
-rw-r--r--chromium/base/test/mock_entropy_provider.cc20
-rw-r--r--chromium/base/test/mock_entropy_provider.h32
-rw-r--r--chromium/base/test/mock_log.cc68
-rw-r--r--chromium/base/test/mock_log.h100
-rw-r--r--chromium/base/test/move_only_int.h68
-rw-r--r--chromium/base/test/multiprocess_test.cc74
-rw-r--r--chromium/base/test/multiprocess_test.h151
-rw-r--r--chromium/base/test/multiprocess_test_android.cc94
-rw-r--r--chromium/base/test/native_library_test_utils.cc19
-rw-r--r--chromium/base/test/native_library_test_utils.h26
-rw-r--r--chromium/base/test/null_task_runner.cc29
-rw-r--r--chromium/base/test/null_task_runner.h44
-rw-r--r--chromium/base/test/perf_log.cc45
-rw-r--r--chromium/base/test/perf_log.h24
-rw-r--r--chromium/base/test/perf_test_suite.cc50
-rw-r--r--chromium/base/test/perf_test_suite.h22
-rw-r--r--chromium/base/test/perf_time_logger.cc27
-rw-r--r--chromium/base/test/perf_time_logger.h37
-rw-r--r--chromium/base/test/power_monitor_test_base.cc65
-rw-r--r--chromium/base/test/power_monitor_test_base.h53
-rw-r--r--chromium/base/test/reached_code_profiler_android.cc25
-rw-r--r--chromium/base/test/run_all_base_unittests.cc15
-rw-r--r--chromium/base/test/run_all_perftests.cc9
-rw-r--r--chromium/base/test/run_all_unittests.cc15
-rw-r--r--chromium/base/test/scoped_command_line.cc22
-rw-r--r--chromium/base/test/scoped_command_line.h34
-rw-r--r--chromium/base/test/scoped_environment_variable_override.cc33
-rw-r--r--chromium/base/test/scoped_environment_variable_override.h40
-rw-r--r--chromium/base/test/scoped_feature_list.cc301
-rw-r--r--chromium/base/test/scoped_feature_list.h152
-rw-r--r--chromium/base/test/scoped_feature_list_unittest.cc430
-rw-r--r--chromium/base/test/scoped_field_trial_list_resetter.cc21
-rw-r--r--chromium/base/test/scoped_field_trial_list_resetter.h36
-rw-r--r--chromium/base/test/scoped_locale.cc23
-rw-r--r--chromium/base/test/scoped_locale.h29
-rw-r--r--chromium/base/test/scoped_mock_clock_override.cc46
-rw-r--r--chromium/base/test/scoped_mock_clock_override.h54
-rw-r--r--chromium/base/test/scoped_mock_clock_override_unittest.cc104
-rw-r--r--chromium/base/test/scoped_mock_time_message_loop_task_runner.cc38
-rw-r--r--chromium/base/test/scoped_mock_time_message_loop_task_runner.h45
-rw-r--r--chromium/base/test/scoped_mock_time_message_loop_task_runner_unittest.cc125
-rw-r--r--chromium/base/test/scoped_os_info_override_win.cc126
-rw-r--r--chromium/base/test/scoped_os_info_override_win.h64
-rw-r--r--chromium/base/test/scoped_path_override.cc40
-rw-r--r--chromium/base/test/scoped_path_override.h43
-rw-r--r--chromium/base/test/scoped_run_loop_timeout.cc94
-rw-r--r--chromium/base/test/scoped_run_loop_timeout.h107
-rw-r--r--chromium/base/test/scoped_run_loop_timeout_unittest.cc79
-rw-r--r--chromium/base/test/sequenced_task_runner_test_template.cc270
-rw-r--r--chromium/base/test/sequenced_task_runner_test_template.h350
-rw-r--r--chromium/base/test/simple_test_clock.cc28
-rw-r--r--chromium/base/test/simple_test_clock.h41
-rw-r--r--chromium/base/test/simple_test_tick_clock.cc31
-rw-r--r--chromium/base/test/simple_test_tick_clock.h41
-rw-r--r--chromium/base/test/spin_wait.h52
-rw-r--r--chromium/base/test/task_environment.cc808
-rw-r--r--chromium/base/test/task_environment.h445
-rw-r--r--chromium/base/test/task_environment_unittest.cc1274
-rw-r--r--chromium/base/test/task_runner_test_template.cc42
-rw-r--r--chromium/base/test/task_runner_test_template.h170
-rw-r--r--chromium/base/test/test_child_process.cc43
-rw-r--r--chromium/base/test/test_discardable_memory_allocator.cc67
-rw-r--r--chromium/base/test/test_discardable_memory_allocator.h38
-rw-r--r--chromium/base/test/test_file_util.cc23
-rw-r--r--chromium/base/test/test_file_util.h85
-rw-r--r--chromium/base/test/test_file_util_android.cc26
-rw-r--r--chromium/base/test/test_file_util_linux.cc60
-rw-r--r--chromium/base/test/test_file_util_mac.cc52
-rw-r--r--chromium/base/test/test_file_util_posix.cc116
-rw-r--r--chromium/base/test/test_file_util_win.cc189
-rw-r--r--chromium/base/test/test_io_thread.cc45
-rw-r--r--chromium/base/test/test_io_thread.h56
-rw-r--r--chromium/base/test/test_listener_ios.h17
-rw-r--r--chromium/base/test/test_listener_ios.mm44
-rw-r--r--chromium/base/test/test_message_loop.cc50
-rw-r--r--chromium/base/test/test_message_loop.h39
-rw-r--r--chromium/base/test/test_mock_time_task_runner.cc501
-rw-r--r--chromium/base/test/test_mock_time_task_runner_unittest.cc298
-rw-r--r--chromium/base/test/test_reg_util_win.cc120
-rw-r--r--chromium/base/test/test_reg_util_win.h82
-rw-r--r--chromium/base/test/test_reg_util_win_unittest.cc134
-rw-r--r--chromium/base/test/test_shared_library.cc30
-rw-r--r--chromium/base/test/test_shared_memory_util.cc169
-rw-r--r--chromium/base/test/test_shared_memory_util.h52
-rw-r--r--chromium/base/test/test_shortcut_win.cc154
-rw-r--r--chromium/base/test/test_shortcut_win.h30
-rw-r--r--chromium/base/test/test_simple_task_runner.cc103
-rw-r--r--chromium/base/test/test_simple_task_runner.h97
-rw-r--r--chromium/base/test/test_suite.cc667
-rw-r--r--chromium/base/test/test_suite.h110
-rw-r--r--chromium/base/test/test_support_android.cc223
-rw-r--r--chromium/base/test/test_support_android.h25
-rw-r--r--chromium/base/test/test_support_ios.h27
-rw-r--r--chromium/base/test/test_support_ios.mm246
-rw-r--r--chromium/base/test/test_switches.cc104
-rw-r--r--chromium/base/test/test_switches.h46
-rw-r--r--chromium/base/test/test_timeouts.cc132
-rw-r--r--chromium/base/test/test_timeouts.h63
-rw-r--r--chromium/base/test/test_waitable_event.cc28
-rw-r--r--chromium/base/test/test_waitable_event.h40
-rw-r--r--chromium/base/test/test_waitable_event_unittest.cc66
-rw-r--r--chromium/base/test/thread_pool_test_helpers_android.cc39
-rw-r--r--chromium/base/test/thread_test_helper.cc41
-rw-r--r--chromium/base/test/thread_test_helper.h50
-rw-r--r--chromium/base/test/trace_event_analyzer.cc1077
-rw-r--r--chromium/base/test/trace_event_analyzer.h842
-rw-r--r--chromium/base/test/trace_event_analyzer_unittest.cc959
-rw-r--r--chromium/base/test/trace_to_file.cc112
-rw-r--r--chromium/base/test/trace_to_file.h35
-rw-r--r--chromium/base/test/values_test_util.cc247
-rw-r--r--chromium/base/test/values_test_util.h105
-rw-r--r--chromium/base/test/with_feature_override.cc32
-rw-r--r--chromium/base/test/with_feature_override.h55
145 files changed, 17167 insertions, 2 deletions
diff --git a/chromium/base/test/BUILD.gn b/chromium/base/test/BUILD.gn
index c48169c1eef..86b11128e51 100644
--- a/chromium/base/test/BUILD.gn
+++ b/chromium/base/test/BUILD.gn
@@ -472,7 +472,7 @@ if (is_android) {
"//base:base_java_test_support",
"//testing/android/native_test:native_main_runner_java",
"//third_party/android_deps:androidx_annotation_annotation_java",
- "//third_party/jsr-305:jsr_305_javalib",
+ "//third_party/android_deps:com_google_code_findbugs_jsr305_java",
]
srcjar_deps = [ ":test_support_java_aidl" ]
sources = [
diff --git a/chromium/base/test/DEPS b/chromium/base/test/DEPS
new file mode 100644
index 00000000000..131691a74ea
--- /dev/null
+++ b/chromium/base/test/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+third_party/libxml/chromium",
+]
diff --git a/chromium/base/test/OWNERS b/chromium/base/test/OWNERS
new file mode 100644
index 00000000000..08d2b4c340d
--- /dev/null
+++ b/chromium/base/test/OWNERS
@@ -0,0 +1,15 @@
+# Metrics-related test utilites:
+per-file *scoped_feature_list*=file://base/metrics/OWNERS
+
+# Tracing test utilities:
+per-file trace_*=file://base/trace_event/OWNERS
+
+#For Windows-specific test utilities:
+per-file *_win*=file://base/win/OWNERS
+
+# For Android-specific changes:
+per-file *android*=file://base/test/android/OWNERS
+per-file BUILD.gn=file://base/test/android/OWNERS
+
+# Linux fontconfig changes
+per-file *fontconfig*=file://base/nix/OWNERS
diff --git a/chromium/base/test/bind_test_util.cc b/chromium/base/test/bind_test_util.cc
new file mode 100644
index 00000000000..9b1cef836e8
--- /dev/null
+++ b/chromium/base/test/bind_test_util.cc
@@ -0,0 +1,72 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/bind_test_util.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+// A helper class for MakeExpectedRunClosure() that fails if it is
+// destroyed without Run() having been called. This class may be used
+// from multiple threads as long as Run() is called at most once
+// before destruction.
+class RunChecker {
+ public:
+ explicit RunChecker(const Location& location,
+ StringPiece message,
+ bool is_repeating)
+ : location_(location),
+ message_(message.as_string()),
+ is_repeating_(is_repeating) {}
+
+ ~RunChecker() {
+ if (!called_) {
+ ADD_FAILURE_AT(location_.file_name(), location_.line_number())
+ << message_;
+ }
+ }
+
+ void Run() {
+ DCHECK(is_repeating_ || !called_);
+ called_ = true;
+ }
+
+ private:
+ const Location location_;
+ const std::string message_;
+ const bool is_repeating_;
+ bool called_ = false;
+};
+
+} // namespace
+
+OnceClosure MakeExpectedRunClosure(const Location& location,
+ StringPiece message) {
+ return BindOnce(&RunChecker::Run,
+ Owned(new RunChecker(location, message, false)));
+}
+
+RepeatingClosure MakeExpectedRunAtLeastOnceClosure(const Location& location,
+ StringPiece message) {
+ return BindRepeating(&RunChecker::Run,
+ Owned(new RunChecker(location, message, true)));
+}
+
+RepeatingClosure MakeExpectedNotRunClosure(const Location& location,
+ StringPiece message) {
+ return BindRepeating(
+ [](const Location& location, StringPiece message) {
+ ADD_FAILURE_AT(location.file_name(), location.line_number()) << message;
+ },
+ location, message.as_string());
+}
+
+} // namespace base
diff --git a/chromium/base/test/bind_test_util.h b/chromium/base/test/bind_test_util.h
new file mode 100644
index 00000000000..85e1f918cff
--- /dev/null
+++ b/chromium/base/test/bind_test_util.h
@@ -0,0 +1,89 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_BIND_TEST_UTIL_H_
+#define BASE_TEST_BIND_TEST_UTIL_H_
+
+#include <type_traits>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+class Location;
+
+namespace internal {
+
+template <typename Callable,
+ typename Signature = decltype(&Callable::operator())>
+struct HasConstCallOperatorImpl : std::false_type {};
+
+template <typename Callable, typename R, typename... Args>
+struct HasConstCallOperatorImpl<Callable, R (Callable::*)(Args...) const>
+ : std::true_type {};
+
+template <typename Callable>
+constexpr bool HasConstCallOperator =
+ HasConstCallOperatorImpl<std::decay_t<Callable>>::value;
+
+template <typename F, typename Signature>
+struct BindLambdaHelper;
+
+template <typename F, typename R, typename... Args>
+struct BindLambdaHelper<F, R(Args...)> {
+ static R Run(const std::decay_t<F>& f, Args... args) {
+ return f(std::forward<Args>(args)...);
+ }
+
+ static R RunOnce(std::decay_t<F>&& f, Args... args) {
+ return f(std::forward<Args>(args)...);
+ }
+};
+
+} // namespace internal
+
+// A variant of BindRepeating() that can bind capturing lambdas for testing.
+// This doesn't support extra arguments binding as the lambda itself can do.
+template <typename Lambda,
+ std::enable_if_t<internal::HasConstCallOperator<Lambda>>* = nullptr>
+decltype(auto) BindLambdaForTesting(Lambda&& lambda) {
+ using Signature = internal::ExtractCallableRunType<std::decay_t<Lambda>>;
+ return BindRepeating(&internal::BindLambdaHelper<Lambda, Signature>::Run,
+ std::forward<Lambda>(lambda));
+}
+
+// A variant of BindRepeating() that can bind mutable capturing lambdas for
+// testing. This doesn't support extra arguments binding as the lambda itself
+// can do. Since a mutable lambda potentially can invalidate its state after
+// being run once, this method returns a OnceCallback instead of a
+// RepeatingCallback.
+template <typename Lambda,
+ std::enable_if_t<!internal::HasConstCallOperator<Lambda>>* = nullptr>
+decltype(auto) BindLambdaForTesting(Lambda&& lambda) {
+ static_assert(
+ std::is_rvalue_reference<Lambda&&>() &&
+ !std::is_const<std::remove_reference_t<Lambda>>(),
+ "BindLambdaForTesting requires non-const rvalue for mutable lambda "
+ "binding. I.e.: base::BindLambdaForTesting(std::move(lambda)).");
+ using Signature = internal::ExtractCallableRunType<std::decay_t<Lambda>>;
+ return BindOnce(&internal::BindLambdaHelper<Lambda, Signature>::RunOnce,
+ std::move(lambda));
+}
+
+// Returns a closure that fails on destruction if it hasn't been run.
+OnceClosure MakeExpectedRunClosure(const Location& location,
+ StringPiece message = StringPiece());
+RepeatingClosure MakeExpectedRunAtLeastOnceClosure(
+ const Location& location,
+ StringPiece message = StringPiece());
+
+// Returns a closure that fails the test if run.
+RepeatingClosure MakeExpectedNotRunClosure(const Location& location,
+ StringPiece message = StringPiece());
+
+} // namespace base
+
+#endif // BASE_TEST_BIND_TEST_UTIL_H_
diff --git a/chromium/base/test/clang_profiling.cc b/chromium/base/test/clang_profiling.cc
new file mode 100644
index 00000000000..5681a105e60
--- /dev/null
+++ b/chromium/base/test/clang_profiling.cc
@@ -0,0 +1,26 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/clang_profiling.h"
+
+#include "base/no_destructor.h"
+#include "base/synchronization/lock.h"
+
+extern "C" int __llvm_profile_dump(void);
+
+namespace base {
+
+void WriteClangProfilingProfile() {
+ // __llvm_profile_dump() guarantees that it will not dump profiling
+ // information if it is being called twice or more. However, it is not thread
+ // safe, as it is supposed to be called from atexit() handler rather than
+ // being called directly from random places. Since we have to call it
+ // ourselves, we must ensure thread safety in order to prevent duplication of
+ // profiling counters.
+ static base::NoDestructor<base::Lock> lock;
+ base::AutoLock auto_lock(*lock);
+ __llvm_profile_dump();
+}
+
+} // namespace base
diff --git a/chromium/base/test/clang_profiling.h b/chromium/base/test/clang_profiling.h
new file mode 100644
index 00000000000..52f48e59653
--- /dev/null
+++ b/chromium/base/test/clang_profiling.h
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_CLANG_PROFILING_H_
+#define BASE_TEST_CLANG_PROFILING_H_
+
+#include "base/clang_profiling_buildflags.h"
+
+#include "base/base_export.h"
+
+#if !BUILDFLAG(CLANG_PROFILING)
+#error "Clang profiling can only be used if CLANG_PROFILING macro is defined"
+#endif
+
+namespace base {
+
+// Write out the accumulated code profiling profile to the configured file.
+// This is used internally by e.g. base::Process and FATAL logging, to cause
+// profiling information to be stored even when performing an "immediate" exit
+// (or triggering a debug crash), where the automatic at-exit writer will not
+// be invoked.
+// This call is thread-safe, and will write profiling data at-most-once.
+BASE_EXPORT void WriteClangProfilingProfile();
+
+} // namespace base
+
+#endif // BASE_TEST_CLANG_PROFILING_H_
diff --git a/chromium/base/test/copy_only_int.cc b/chromium/base/test/copy_only_int.cc
new file mode 100644
index 00000000000..d135a861fe8
--- /dev/null
+++ b/chromium/base/test/copy_only_int.cc
@@ -0,0 +1,12 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/copy_only_int.h"
+
+namespace base {
+
+// static
+int CopyOnlyInt::num_copies_ = 0;
+
+} // namespace base
diff --git a/chromium/base/test/copy_only_int.h b/chromium/base/test/copy_only_int.h
new file mode 100644
index 00000000000..5cd969cf1c2
--- /dev/null
+++ b/chromium/base/test/copy_only_int.h
@@ -0,0 +1,61 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_COPY_ONLY_INT_H_
+#define BASE_TEST_COPY_ONLY_INT_H_
+
+#include "base/macros.h"
+
+namespace base {
+
+// A copy-only (not moveable) class that holds an integer. This is designed for
+// testing containers. See also MoveOnlyInt.
+class CopyOnlyInt {
+ public:
+ explicit CopyOnlyInt(int data = 1) : data_(data) {}
+ CopyOnlyInt(const CopyOnlyInt& other) : data_(other.data_) { ++num_copies_; }
+ ~CopyOnlyInt() { data_ = 0; }
+
+ friend bool operator==(const CopyOnlyInt& lhs, const CopyOnlyInt& rhs) {
+ return lhs.data_ == rhs.data_;
+ }
+
+ friend bool operator!=(const CopyOnlyInt& lhs, const CopyOnlyInt& rhs) {
+ return !operator==(lhs, rhs);
+ }
+
+ friend bool operator<(const CopyOnlyInt& lhs, const CopyOnlyInt& rhs) {
+ return lhs.data_ < rhs.data_;
+ }
+
+ friend bool operator>(const CopyOnlyInt& lhs, const CopyOnlyInt& rhs) {
+ return rhs < lhs;
+ }
+
+ friend bool operator<=(const CopyOnlyInt& lhs, const CopyOnlyInt& rhs) {
+ return !(rhs < lhs);
+ }
+
+ friend bool operator>=(const CopyOnlyInt& lhs, const CopyOnlyInt& rhs) {
+ return !(lhs < rhs);
+ }
+
+ int data() const { return data_; }
+
+ static void reset_num_copies() { num_copies_ = 0; }
+
+ static int num_copies() { return num_copies_; }
+
+ private:
+ volatile int data_;
+
+ static int num_copies_;
+
+ CopyOnlyInt(CopyOnlyInt&&) = delete;
+ CopyOnlyInt& operator=(CopyOnlyInt&) = delete;
+};
+
+} // namespace base
+
+#endif // BASE_TEST_COPY_ONLY_INT_H_
diff --git a/chromium/base/test/fontconfig_util_linux.cc b/chromium/base/test/fontconfig_util_linux.cc
index b7bf9e65f70..4f6c1c71349 100644
--- a/chromium/base/test/fontconfig_util_linux.cc
+++ b/chromium/base/test/fontconfig_util_linux.cc
@@ -9,9 +9,9 @@
#include <memory>
#include "base/base_paths.h"
+#include "base/check.h"
#include "base/environment.h"
#include "base/files/file_path.h"
-#include "base/logging.h"
#include "base/path_service.h"
namespace base {
diff --git a/chromium/base/test/generate_fontconfig_caches.cc b/chromium/base/test/generate_fontconfig_caches.cc
new file mode 100644
index 00000000000..cd01d551ef0
--- /dev/null
+++ b/chromium/base/test/generate_fontconfig_caches.cc
@@ -0,0 +1,66 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fontconfig/fontconfig.h>
+#include <string.h>
+#include <time.h>
+#include <utime.h>
+
+#include <string>
+
+#include "base/base_paths.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/strings/strcat.h"
+#include "base/test/fontconfig_util_linux.h"
+
+// GIANT WARNING: The point of this file is to front-load construction of the
+// font cache [which takes 600ms] from test run time to compile time. This saves
+// 600ms on each test shard which uses the font cache into compile time. The
+// problem is that fontconfig cache construction is not intended to be
+// deterministic. This executable tries to set some external state to ensure
+// determinism. We have no way of guaranteeing that this produces correct
+// results, or even has the intended effect.
+int main() {
+ // fontconfig generates a random uuid and uses it to match font folders with
+ // the font cache. Rather than letting fontconfig generate a random uuid,
+ // which introduces build non-determinism, we place a fixed uuid in the font
+ // folder, which fontconfig will use to generate the cache.
+ base::FilePath dir_module;
+ base::PathService::Get(base::DIR_MODULE, &dir_module);
+ base::FilePath uuid_file_path =
+ dir_module.Append("test_fonts").Append(".uuid");
+ const char uuid[] = "fb5c91b2895aa445d23aebf7f9e2189c";
+ WriteFile(uuid_file_path, uuid);
+
+ // fontconfig writes the mtime of the test_fonts directory into the cache. It
+ // presumably checks this later to ensure that the cache is still up to date.
+ // We set the mtime to an arbitrary, fixed time in the past.
+ base::FilePath test_fonts_file_path = dir_module.Append("test_fonts");
+ base::stat_wrapper_t old_times;
+ struct utimbuf new_times;
+
+ base::File::Stat(test_fonts_file_path.value().c_str(), &old_times);
+ new_times.actime = old_times.st_atime;
+ // Use an arbitrary, fixed time.
+ new_times.modtime = 123456789;
+ utime(test_fonts_file_path.value().c_str(), &new_times);
+
+ base::FilePath fontconfig_caches = dir_module.Append("fontconfig_caches");
+
+ // Delete directory before generating fontconfig caches. This will notify
+ // future fontconfig_caches changes.
+ CHECK(base::DeleteFileRecursively(fontconfig_caches));
+
+ base::SetUpFontconfig();
+ FcInit();
+ FcFini();
+
+ // Check existence of intended fontconfig cache file.
+ CHECK(base::PathExists(
+ fontconfig_caches.Append(base::StrCat({uuid, "-le64.cache-7"}))));
+ return 0;
+}
diff --git a/chromium/base/test/gmock_callback_support.h b/chromium/base/test/gmock_callback_support.h
new file mode 100644
index 00000000000..61b880d9475
--- /dev/null
+++ b/chromium/base/test/gmock_callback_support.h
@@ -0,0 +1,150 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_GMOCK_CALLBACK_SUPPORT_H_
+#define BASE_TEST_GMOCK_CALLBACK_SUPPORT_H_
+
+#include <functional>
+#include <tuple>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace base {
+namespace test {
+
+// TODO(crbug.com/752720): Simplify using std::apply once C++17 is available.
+template <typename CallbackFunc, typename ArgTuple, size_t... I>
+decltype(auto) RunOnceCallbackUnwrapped(CallbackFunc&& f,
+ ArgTuple&& t,
+ std::index_sequence<I...>) {
+ return std::move(f).Run(std::get<I>(t)...);
+}
+
+// TODO(crbug.com/752720): Simplify using std::apply once C++17 is available.
+template <typename CallbackFunc, typename ArgTuple, size_t... I>
+decltype(auto) RunRepeatingCallbackUnwrapped(CallbackFunc&& f,
+ ArgTuple&& t,
+ std::index_sequence<I...>) {
+ return f.Run(std::get<I>(t)...);
+}
+
+// Functor used for RunOnceClosure<N>() and RunOnceCallback<N>() actions.
+template <size_t I, typename... Vals>
+struct RunOnceCallbackAction {
+ std::tuple<Vals...> vals;
+
+ template <typename... Args>
+ decltype(auto) operator()(Args&&... args) {
+ constexpr size_t size = std::tuple_size<decltype(vals)>::value;
+ return RunOnceCallbackUnwrapped(
+ std::get<I>(std::forward_as_tuple(std::forward<Args>(args)...)),
+ std::move(vals), std::make_index_sequence<size>{});
+ }
+};
+
+// Functor used for RunClosure<N>() and RunCallback<N>() actions.
+template <size_t I, typename... Vals>
+struct RunRepeatingCallbackAction {
+ std::tuple<Vals...> vals;
+
+ template <typename... Args>
+ decltype(auto) operator()(Args&&... args) {
+ constexpr size_t size = std::tuple_size<decltype(vals)>::value;
+ return RunRepeatingCallbackUnwrapped(
+ std::get<I>(std::forward_as_tuple(std::forward<Args>(args)...)),
+ std::move(vals), std::make_index_sequence<size>{});
+ }
+};
+
+// Matchers for base::{Once,Repeating}Callback and
+// base::{Once,Repeating}Closure.
+MATCHER(IsNullCallback, "a null callback") {
+ return (arg.is_null());
+}
+
+MATCHER(IsNotNullCallback, "a non-null callback") {
+ return (!arg.is_null());
+}
+
+// The Run[Once]Closure() action invokes the Run() method on the closure
+// provided when the action is constructed. Function arguments passed when the
+// action is run will be ignored.
+ACTION_P(RunClosure, closure) {
+ closure.Run();
+}
+
+// This action can be invoked at most once. Any further invocation will trigger
+// a CHECK failure.
+inline auto RunOnceClosure(base::OnceClosure cb) {
+ // Mock actions need to be copyable, but OnceClosure is not. Wrap the closure
+ // in a base::RefCountedData<> to allow it to be copied. An alternative would
+ // be to use AdaptCallbackForRepeating(), but that allows the closure to be
+ // run more than once and silently ignores any invocation after the first.
+ // Since this is for use by tests, it's better to crash or CHECK-fail and
+ // surface the incorrect usage, rather than have a silent unexpected success.
+ using RefCountedOnceClosure = base::RefCountedData<base::OnceClosure>;
+ scoped_refptr<RefCountedOnceClosure> copyable_cb =
+ base::MakeRefCounted<RefCountedOnceClosure>(std::move(cb));
+ return [copyable_cb](auto&&...) {
+ CHECK(copyable_cb->data);
+ std::move(copyable_cb->data).Run();
+ };
+}
+
+// The Run[Once]Closure<N>() action invokes the Run() method on the N-th
+// (0-based) argument of the mock function.
+template <size_t I>
+RunRepeatingCallbackAction<I> RunClosure() {
+ return {};
+}
+
+template <size_t I>
+RunOnceCallbackAction<I> RunOnceClosure() {
+ return {};
+}
+
+// The Run[Once]Callback<N>(p1, p2, ..., p_k) action invokes the Run() method on
+// the N-th (0-based) argument of the mock function, with arguments p1, p2, ...,
+// p_k.
+//
+// Notes:
+//
+// 1. The arguments are passed by value by default. If you need to
+// pass an argument by reference, wrap it inside ByRef(). For example,
+//
+// RunCallback<1>(5, string("Hello"), ByRef(foo))
+//
+// passes 5 and string("Hello") by value, and passes foo by reference.
+//
+// 2. If the callback takes an argument by reference but ByRef() is
+// not used, it will receive the reference to a copy of the value,
+// instead of the original value. For example, when the 0-th
+// argument of the callback takes a const string&, the action
+//
+// RunCallback<0>(string("Hello"))
+//
+// makes a copy of the temporary string("Hello") object and passes a
+// reference of the copy, instead of the original temporary object,
+// to the callback. This makes it easy for a user to define an
+// RunCallback action from temporary values and have it performed later.
+template <size_t I, typename... Vals>
+RunOnceCallbackAction<I, std::decay_t<Vals>...> RunOnceCallback(
+ Vals&&... vals) {
+ return {std::forward_as_tuple(std::forward<Vals>(vals)...)};
+}
+
+template <size_t I, typename... Vals>
+RunRepeatingCallbackAction<I, std::decay_t<Vals>...> RunCallback(
+ Vals&&... vals) {
+ return {std::forward_as_tuple(std::forward<Vals>(vals)...)};
+}
+
+} // namespace test
+} // namespace base
+
+#endif // BASE_TEST_GMOCK_CALLBACK_SUPPORT_H_
diff --git a/chromium/base/test/gmock_callback_support_unittest.cc b/chromium/base/test/gmock_callback_support_unittest.cc
new file mode 100644
index 00000000000..5aa95595427
--- /dev/null
+++ b/chromium/base/test/gmock_callback_support_unittest.cc
@@ -0,0 +1,178 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/gmock_callback_support.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::ByRef;
+using testing::MockFunction;
+
+namespace base {
+namespace test {
+
+using TestCallback = base::RepeatingCallback<void(const bool& src, bool* dst)>;
+using TestOnceCallback = base::OnceCallback<void(const bool& src, bool* dst)>;
+
+void SetBool(const bool& src, bool* dst) {
+ *dst = src;
+}
+
+TEST(GmockCallbackSupportTest, IsNullCallback) {
+ MockFunction<void(const TestCallback&)> check;
+ EXPECT_CALL(check, Call(IsNullCallback()));
+ check.Call(TestCallback());
+}
+
+TEST(GmockCallbackSupportTest, IsNotNullCallback) {
+ MockFunction<void(const TestCallback&)> check;
+ EXPECT_CALL(check, Call(IsNotNullCallback()));
+ check.Call(base::BindRepeating(&SetBool));
+}
+
+TEST(GmockCallbackSupportTest, IsNullOnceCallback) {
+ MockFunction<void(TestOnceCallback)> mock;
+ EXPECT_CALL(mock, Call(IsNullCallback()));
+ mock.Call(TestOnceCallback());
+}
+
+TEST(GmockCallbackSupportTest, IsNotNullOnceCallback) {
+ MockFunction<void(TestOnceCallback)> mock;
+ EXPECT_CALL(mock, Call(IsNotNullCallback()));
+ mock.Call(base::BindOnce(&SetBool));
+}
+
+TEST(GmockCallbackSupportTest, RunClosure0) {
+ MockFunction<void(const base::RepeatingClosure&)> check;
+ bool dst = false;
+ EXPECT_CALL(check, Call(IsNotNullCallback())).WillOnce(RunClosure<0>());
+ check.Call(base::BindRepeating(&SetBool, true, &dst));
+ EXPECT_TRUE(dst);
+}
+
+TEST(GmockCallbackSupportTest, RunClosureByRefNotReset) {
+ // Check that RepeatingClosure isn't reset by RunClosure<N>().
+ MockFunction<void(base::RepeatingClosure&)> check;
+ bool dst = false;
+ EXPECT_CALL(check, Call(IsNotNullCallback())).WillOnce(RunClosure<0>());
+ auto closure = base::BindRepeating(&SetBool, true, &dst);
+ check.Call(closure);
+ EXPECT_TRUE(dst);
+ EXPECT_FALSE(closure.is_null());
+}
+
+TEST(GmockCallbackSupportTest, RunCallback0) {
+ MockFunction<void(const TestCallback&)> check;
+ bool dst = false;
+ EXPECT_CALL(check, Call(IsNotNullCallback()))
+ .WillOnce(RunCallback<0>(true, &dst));
+ check.Call(base::BindRepeating(&SetBool));
+ EXPECT_TRUE(dst);
+}
+
+TEST(GmockCallbackSupportTest, RunCallback1) {
+ MockFunction<void(int, const TestCallback&)> check;
+ bool dst = false;
+ EXPECT_CALL(check, Call(0, IsNotNullCallback()))
+ .WillOnce(RunCallback<1>(true, &dst));
+ check.Call(0, base::BindRepeating(&SetBool));
+ EXPECT_TRUE(dst);
+}
+
+TEST(GmockCallbackSupportTest, RunCallbackPassByRef) {
+ MockFunction<void(const TestCallback&)> check;
+ bool dst = false;
+ bool src = false;
+ EXPECT_CALL(check, Call(IsNotNullCallback()))
+ .WillOnce(RunCallback<0>(ByRef(src), &dst));
+ src = true;
+ check.Call(base::BindRepeating(&SetBool));
+ EXPECT_TRUE(dst);
+}
+
+TEST(GmockCallbackSupportTest, RunCallbackPassByValue) {
+ MockFunction<void(const TestCallback&)> check;
+ bool dst = false;
+ bool src = true;
+ EXPECT_CALL(check, Call(IsNotNullCallback()))
+ .WillOnce(RunCallback<0>(src, &dst));
+ src = false;
+ check.Call(base::BindRepeating(&SetBool));
+ EXPECT_TRUE(dst);
+}
+
+TEST(GmockCallbackSupportTest, RunOnceClosure0) {
+ MockFunction<void(base::OnceClosure)> check;
+ bool dst = false;
+ EXPECT_CALL(check, Call(IsNotNullCallback())).WillOnce(RunOnceClosure<0>());
+ check.Call(base::BindOnce(&SetBool, true, &dst));
+ EXPECT_TRUE(dst);
+}
+
+TEST(GmockCallbackSupportTest, RunOnceCallback0) {
+ MockFunction<void(TestOnceCallback)> check;
+ bool dst = false;
+ bool src = true;
+ EXPECT_CALL(check, Call(IsNotNullCallback()))
+ .WillOnce(RunOnceCallback<0>(src, &dst));
+ src = false;
+ check.Call(base::BindOnce(&SetBool));
+ EXPECT_TRUE(dst);
+}
+
+TEST(GmockCallbackSupportTest, RunClosureValue) {
+ MockFunction<void()> check;
+ bool dst = false;
+ EXPECT_CALL(check, Call())
+ .WillOnce(RunClosure(base::BindRepeating(&SetBool, true, &dst)));
+ check.Call();
+ EXPECT_TRUE(dst);
+}
+
+TEST(GmockCallbackSupportTest, RunClosureValueWithArgs) {
+ MockFunction<void(bool, int)> check;
+ bool dst = false;
+ EXPECT_CALL(check, Call(true, 42))
+ .WillOnce(RunClosure(base::BindRepeating(&SetBool, true, &dst)));
+ check.Call(true, 42);
+ EXPECT_TRUE(dst);
+}
+
+TEST(GmockCallbackSupportTest, RunOnceClosureValue) {
+ MockFunction<void()> check;
+ bool dst = false;
+ EXPECT_CALL(check, Call())
+ .WillOnce(RunOnceClosure(base::BindOnce(&SetBool, true, &dst)));
+ check.Call();
+ EXPECT_TRUE(dst);
+}
+
+TEST(GmockCallbackSupportTest, RunOnceClosureValueWithArgs) {
+ MockFunction<void(bool, int)> check;
+ bool dst = false;
+ EXPECT_CALL(check, Call(true, 42))
+ .WillOnce(RunOnceClosure(base::BindOnce(&SetBool, true, &dst)));
+ check.Call(true, 42);
+ EXPECT_TRUE(dst);
+}
+
+TEST(GmockCallbackSupportTest, RunOnceClosureValueMultipleCall) {
+ MockFunction<void()> check;
+ bool dst = false;
+ EXPECT_CALL(check, Call())
+ .WillRepeatedly(RunOnceClosure(base::BindOnce(&SetBool, true, &dst)));
+ check.Call();
+ EXPECT_TRUE(dst);
+
+ // Invoking the RunOnceClosure action more than once will trigger a
+ // CHECK-failure.
+ dst = false;
+ EXPECT_DEATH_IF_SUPPORTED(check.Call(), "");
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/gmock_move_support.h b/chromium/base/test/gmock_move_support.h
new file mode 100644
index 00000000000..8af9b219abe
--- /dev/null
+++ b/chromium/base/test/gmock_move_support.h
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_GMOCK_MOVE_SUPPORT_H_
+#define BASE_TEST_GMOCK_MOVE_SUPPORT_H_
+
+#include <tuple>
+#include <utility>
+
+// A similar action as testing::SaveArg, but it does an assignment with
+// std::move() instead of always performing a copy.
+template <size_t I = 0, typename T>
+auto MoveArg(T* out) {
+ return [out](auto&&... args) {
+ *out = std::move(std::get<I>(std::tie(args...)));
+ };
+}
+
+#endif // BASE_TEST_GMOCK_MOVE_SUPPORT_H_
diff --git a/chromium/base/test/gmock_move_support_unittest.cc b/chromium/base/test/gmock_move_support_unittest.cc
new file mode 100644
index 00000000000..e72fed77ca6
--- /dev/null
+++ b/chromium/base/test/gmock_move_support_unittest.cc
@@ -0,0 +1,60 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/gmock_move_support.h"
+
+#include <memory>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using ::testing::DoAll;
+using ::testing::Pointee;
+
+using MoveOnly = std::unique_ptr<int>;
+
+struct MockFoo {
+ MOCK_METHOD(void, ByRef, (MoveOnly&), ());
+ MOCK_METHOD(void, ByVal, (MoveOnly), ());
+ MOCK_METHOD(void, TwiceByRef, (MoveOnly&, MoveOnly&), ());
+};
+} // namespace
+
+TEST(GmockMoveSupportTest, MoveArgByRef) {
+ MoveOnly result;
+
+ MockFoo foo;
+ EXPECT_CALL(foo, ByRef).WillOnce(MoveArg(&result));
+ MoveOnly arg = std::make_unique<int>(123);
+ foo.ByRef(arg);
+
+ EXPECT_THAT(result, Pointee(123));
+}
+
+TEST(GmockMoveSupportTest, MoveArgByVal) {
+ MoveOnly result;
+
+ MockFoo foo;
+ EXPECT_CALL(foo, ByVal).WillOnce(MoveArg(&result));
+ foo.ByVal(std::make_unique<int>(456));
+
+ EXPECT_THAT(result, Pointee(456));
+}
+
+TEST(GmockMoveSupportTest, MoveArgsTwiceByRef) {
+ MoveOnly result1;
+ MoveOnly result2;
+
+ MockFoo foo;
+ EXPECT_CALL(foo, TwiceByRef)
+ .WillOnce(DoAll(MoveArg<0>(&result1), MoveArg<1>(&result2)));
+ MoveOnly arg1 = std::make_unique<int>(123);
+ MoveOnly arg2 = std::make_unique<int>(456);
+ foo.TwiceByRef(arg1, arg2);
+
+ EXPECT_THAT(result1, Pointee(123));
+ EXPECT_THAT(result2, Pointee(456));
+}
diff --git a/chromium/base/test/gtest_util.cc b/chromium/base/test/gtest_util.cc
new file mode 100644
index 00000000000..5eeda3958b7
--- /dev/null
+++ b/chromium/base/test/gtest_util.cc
@@ -0,0 +1,111 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/gtest_util.h"
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TestIdentifier::TestIdentifier() = default;
+
+TestIdentifier::TestIdentifier(const TestIdentifier& other) = default;
+
+std::string FormatFullTestName(const std::string& test_case_name,
+ const std::string& test_name) {
+ return test_case_name + "." + test_name;
+}
+
+std::string TestNameWithoutDisabledPrefix(const std::string& full_test_name) {
+ std::string test_name_no_disabled(full_test_name);
+ ReplaceSubstringsAfterOffset(&test_name_no_disabled, 0, "DISABLED_", "");
+ return test_name_no_disabled;
+}
+
+std::vector<TestIdentifier> GetCompiledInTests() {
+ testing::UnitTest* const unit_test = testing::UnitTest::GetInstance();
+
+ std::vector<TestIdentifier> tests;
+ for (int i = 0; i < unit_test->total_test_case_count(); ++i) {
+ const testing::TestCase* test_case = unit_test->GetTestCase(i);
+ for (int j = 0; j < test_case->total_test_count(); ++j) {
+ const testing::TestInfo* test_info = test_case->GetTestInfo(j);
+ TestIdentifier test_data;
+ test_data.test_case_name = test_case->name();
+ test_data.test_name = test_info->name();
+ test_data.file = test_info->file();
+ test_data.line = test_info->line();
+ tests.push_back(test_data);
+ }
+ }
+ return tests;
+}
+
+bool WriteCompiledInTestsToFile(const FilePath& path) {
+ std::vector<TestIdentifier> tests(GetCompiledInTests());
+
+ ListValue root;
+ for (const auto& i : tests) {
+ std::unique_ptr<DictionaryValue> test_info(new DictionaryValue);
+ test_info->SetStringKey("test_case_name", i.test_case_name);
+ test_info->SetStringKey("test_name", i.test_name);
+ test_info->SetStringKey("file", i.file);
+ test_info->SetIntKey("line", i.line);
+ root.Append(std::move(test_info));
+ }
+
+ JSONFileValueSerializer serializer(path);
+ return serializer.Serialize(root);
+}
+
+bool ReadTestNamesFromFile(const FilePath& path,
+ std::vector<TestIdentifier>* output) {
+ JSONFileValueDeserializer deserializer(path);
+ int error_code = 0;
+ std::string error_message;
+ std::unique_ptr<base::Value> value =
+ deserializer.Deserialize(&error_code, &error_message);
+ if (!value.get())
+ return false;
+
+ base::ListValue* tests = nullptr;
+ if (!value->GetAsList(&tests))
+ return false;
+
+ std::vector<base::TestIdentifier> result;
+ for (const auto& i : *tests) {
+ const base::DictionaryValue* test = nullptr;
+ if (!i.GetAsDictionary(&test))
+ return false;
+
+ TestIdentifier test_data;
+
+ if (!test->GetStringASCII("test_case_name", &test_data.test_case_name))
+ return false;
+
+ if (!test->GetStringASCII("test_name", &test_data.test_name))
+ return false;
+
+ if (!test->GetStringASCII("file", &test_data.file))
+ return false;
+
+ if (!test->GetInteger("line", &test_data.line))
+ return false;
+
+ result.push_back(test_data);
+ }
+
+ output->swap(result);
+ return true;
+}
+
+} // namespace base
diff --git a/chromium/base/test/gtest_util.h b/chromium/base/test/gtest_util.h
new file mode 100644
index 00000000000..1db1fae1e2d
--- /dev/null
+++ b/chromium/base/test/gtest_util.h
@@ -0,0 +1,114 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_GTEST_UTIL_H_
+#define BASE_TEST_GTEST_UTIL_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// EXPECT/ASSERT_DCHECK_DEATH is intended to replace EXPECT/ASSERT_DEBUG_DEATH
+// when the death is expected to be caused by a DCHECK. Contrary to
+// EXPECT/ASSERT_DEBUG_DEATH however, it doesn't execute the statement in non-
+// dcheck builds as DCHECKs are intended to catch things that should never
+// happen and as such executing the statement results in undefined behavior
+// (|statement| is compiled in unsupported configurations nonetheless).
+// Death tests misbehave on Android.
+#if DCHECK_IS_ON() && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+
+// EXPECT/ASSERT_DCHECK_DEATH tests verify that a DCHECK is hit ("Check failed"
+// is part of the error message), but intentionally do not expose the gtest
+// death test's full |regex| parameter to avoid users having to verify the exact
+// syntax of the error message produced by the DCHECK.
+
+// Official builds will eat stream parameters, so don't check the error message.
+#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
+#define EXPECT_DCHECK_DEATH(statement) EXPECT_DEATH(statement, "")
+#define ASSERT_DCHECK_DEATH(statement) ASSERT_DEATH(statement, "")
+#else
+#define EXPECT_DCHECK_DEATH(statement) EXPECT_DEATH(statement, "Check failed")
+#define ASSERT_DCHECK_DEATH(statement) ASSERT_DEATH(statement, "Check failed")
+#endif // defined(OFFICIAL_BUILD) && defined(NDEBUG)
+
+#else
+// DCHECK_IS_ON() && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+
+#define EXPECT_DCHECK_DEATH(statement) \
+ GTEST_UNSUPPORTED_DEATH_TEST(statement, "Check failed", )
+#define ASSERT_DCHECK_DEATH(statement) \
+ GTEST_UNSUPPORTED_DEATH_TEST(statement, "Check failed", return)
+
+#endif
+// DCHECK_IS_ON() && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+
+// As above, but for CHECK().
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+
+// Official builds will eat stream parameters, so don't check the error message.
+#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
+#define EXPECT_CHECK_DEATH(statement) EXPECT_DEATH(statement, "")
+#define ASSERT_CHECK_DEATH(statement) ASSERT_DEATH(statement, "")
+#else
+#define EXPECT_CHECK_DEATH(statement) EXPECT_DEATH(statement, "Check failed")
+#define ASSERT_CHECK_DEATH(statement) ASSERT_DEATH(statement, "Check failed")
+#endif // defined(OFFICIAL_BUILD) && defined(NDEBUG)
+
+#else // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+
+// Note GTEST_UNSUPPORTED_DEATH_TEST takes a |regex| only to see whether it is a
+// valid regex. It is never evaluated.
+#define EXPECT_CHECK_DEATH(statement) \
+ GTEST_UNSUPPORTED_DEATH_TEST(statement, "", )
+#define ASSERT_CHECK_DEATH(statement) \
+ GTEST_UNSUPPORTED_DEATH_TEST(statement, "", return )
+
+#endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+
+namespace base {
+
+class FilePath;
+
+struct TestIdentifier {
+ TestIdentifier();
+ TestIdentifier(const TestIdentifier& other);
+
+ std::string test_case_name;
+ std::string test_name;
+ std::string file;
+ int line;
+};
+
+// Constructs a full test name given a test case name and a test name,
+// e.g. for test case "A" and test name "B" returns "A.B".
+std::string FormatFullTestName(const std::string& test_case_name,
+ const std::string& test_name);
+
+// Returns the full test name with the "DISABLED_" prefix stripped out.
+// e.g. for the full test names "A.DISABLED_B", "DISABLED_A.B", and
+// "DISABLED_A.DISABLED_B", returns "A.B".
+std::string TestNameWithoutDisabledPrefix(const std::string& full_test_name);
+
+// Returns a vector of gtest-based tests compiled into
+// current executable.
+std::vector<TestIdentifier> GetCompiledInTests();
+
+// Writes the list of gtest-based tests compiled into
+// current executable as a JSON file. Returns true on success.
+bool WriteCompiledInTestsToFile(const FilePath& path) WARN_UNUSED_RESULT;
+
+// Reads the list of gtest-based tests from |path| into |output|.
+// Returns true on success.
+bool ReadTestNamesFromFile(
+ const FilePath& path,
+ std::vector<TestIdentifier>* output) WARN_UNUSED_RESULT;
+
+} // namespace base
+
+#endif // BASE_TEST_GTEST_UTIL_H_
diff --git a/chromium/base/test/gtest_xml_unittest_result_printer.cc b/chromium/base/test/gtest_xml_unittest_result_printer.cc
new file mode 100644
index 00000000000..709450b5329
--- /dev/null
+++ b/chromium/base/test/gtest_xml_unittest_result_printer.cc
@@ -0,0 +1,165 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/gtest_xml_unittest_result_printer.h"
+
+#include "base/base64.h"
+#include "base/check.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/test/test_switches.h"
+#include "base/time/time.h"
+
+namespace base {
+
+namespace {
+const int kDefaultTestPartResultsLimit = 10;
+
+const char kTestPartLesultsLimitExceeded[] =
+ "Test part results limit exceeded. Use --test-launcher-test-part-limit to "
+ "increase or disable limit.";
+} // namespace
+
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter()
+ : output_file_(nullptr), open_failed_(false) {}
+
+XmlUnitTestResultPrinter::~XmlUnitTestResultPrinter() {
+ if (output_file_ && !open_failed_) {
+ fprintf(output_file_, "</testsuites>\n");
+ fflush(output_file_);
+ CloseFile(output_file_);
+ }
+}
+
+bool XmlUnitTestResultPrinter::Initialize(const FilePath& output_file_path) {
+ DCHECK(!output_file_);
+ output_file_ = OpenFile(output_file_path, "w");
+ if (!output_file_) {
+ // If the file open fails, we set the output location to stderr. This is
+ // because in current usage our caller CHECKs the result of this function.
+ // But that in turn causes a LogMessage that comes back to this object,
+ // which in turn causes a (double) crash. By pointing at stderr, there might
+ // be some indication what's going wrong. See https://crbug.com/736783.
+ output_file_ = stderr;
+ open_failed_ = true;
+ return false;
+ }
+
+ fprintf(output_file_,
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<testsuites>\n");
+ fflush(output_file_);
+
+ return true;
+}
+
+void XmlUnitTestResultPrinter::OnAssert(const char* file,
+ int line,
+ const std::string& summary,
+ const std::string& message) {
+ WriteTestPartResult(file, line, testing::TestPartResult::kFatalFailure,
+ summary, message);
+}
+
+void XmlUnitTestResultPrinter::OnTestCaseStart(
+ const testing::TestCase& test_case) {
+ fprintf(output_file_, " <testsuite>\n");
+ fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestStart(
+ const testing::TestInfo& test_info) {
+ // This is our custom extension - it helps to recognize which test was
+ // running when the test binary crashed. Note that we cannot even open the
+ // <testcase> tag here - it requires e.g. run time of the test to be known.
+ fprintf(output_file_,
+ " <x-teststart name=\"%s\" classname=\"%s\" />\n",
+ test_info.name(),
+ test_info.test_case_name());
+ fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestEnd(const testing::TestInfo& test_info) {
+ fprintf(output_file_,
+ " <testcase name=\"%s\" status=\"run\" time=\"%.3f\""
+ " classname=\"%s\">\n",
+ test_info.name(),
+ static_cast<double>(test_info.result()->elapsed_time()) /
+ Time::kMillisecondsPerSecond,
+ test_info.test_case_name());
+ if (test_info.result()->Failed()) {
+ fprintf(output_file_,
+ " <failure message=\"\" type=\"\"></failure>\n");
+ }
+
+ int limit = test_info.result()->total_part_count();
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kTestLauncherTestPartResultsLimit)) {
+ std::string limit_str =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kTestLauncherTestPartResultsLimit);
+ int test_part_results_limit = std::strtol(limit_str.c_str(), nullptr, 10);
+ if (test_part_results_limit >= 0)
+ limit = std::min(limit, test_part_results_limit);
+ } else {
+ limit = std::min(limit, kDefaultTestPartResultsLimit);
+ }
+
+ for (int i = 0; i < limit; ++i) {
+ const auto& test_part_result = test_info.result()->GetTestPartResult(i);
+ WriteTestPartResult(test_part_result.file_name(),
+ test_part_result.line_number(), test_part_result.type(),
+ test_part_result.summary(), test_part_result.message());
+ }
+
+ if (test_info.result()->total_part_count() > limit) {
+ WriteTestPartResult(
+ "unknown", 0, testing::TestPartResult::kNonFatalFailure,
+ kTestPartLesultsLimitExceeded, kTestPartLesultsLimitExceeded);
+ }
+
+ fprintf(output_file_, " </testcase>\n");
+ fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestCaseEnd(
+ const testing::TestCase& test_case) {
+ fprintf(output_file_, " </testsuite>\n");
+ fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::WriteTestPartResult(
+ const char* file,
+ int line,
+ testing::TestPartResult::Type result_type,
+ const std::string& summary,
+ const std::string& message) {
+ const char* type = "unknown";
+ switch (result_type) {
+ case testing::TestPartResult::kSuccess:
+ type = "success";
+ break;
+ case testing::TestPartResult::kNonFatalFailure:
+ type = "failure";
+ break;
+ case testing::TestPartResult::kFatalFailure:
+ type = "fatal_failure";
+ break;
+ case testing::TestPartResult::kSkip:
+ type = "skip";
+ break;
+ }
+ std::string summary_encoded;
+ Base64Encode(summary, &summary_encoded);
+ std::string message_encoded;
+ Base64Encode(message, &message_encoded);
+ fprintf(output_file_,
+ " <x-test-result-part type=\"%s\" file=\"%s\" line=\"%d\">\n"
+ " <summary>%s</summary>\n"
+ " <message>%s</message>\n"
+ " </x-test-result-part>\n",
+ type, file, line, summary_encoded.c_str(), message_encoded.c_str());
+ fflush(output_file_);
+}
+
+} // namespace base
diff --git a/chromium/base/test/gtest_xml_unittest_result_printer.h b/chromium/base/test/gtest_xml_unittest_result_printer.h
new file mode 100644
index 00000000000..93403822cfa
--- /dev/null
+++ b/chromium/base/test/gtest_xml_unittest_result_printer.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_GTEST_XML_UNITTEST_RESULT_PRINTER_H_
+#define BASE_TEST_GTEST_XML_UNITTEST_RESULT_PRINTER_H_
+
+#include <stdio.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class FilePath;
+
+// Generates an XML output file. Format is very close to GTest, but has
+// extensions needed by the test launcher.
+class XmlUnitTestResultPrinter : public testing::EmptyTestEventListener {
+ public:
+ XmlUnitTestResultPrinter();
+ ~XmlUnitTestResultPrinter() override;
+
+ // Must be called before adding as a listener. Returns true on success.
+ bool Initialize(const FilePath& output_file_path) WARN_UNUSED_RESULT;
+
+ // CHECK/DCHECK failed. Print file/line and message to the xml.
+ void OnAssert(const char* file,
+ int line,
+ const std::string& summary,
+ const std::string& message);
+
+ private:
+ // testing::EmptyTestEventListener:
+ void OnTestCaseStart(const testing::TestCase& test_case) override;
+ void OnTestStart(const testing::TestInfo& test_info) override;
+ void OnTestEnd(const testing::TestInfo& test_info) override;
+ void OnTestCaseEnd(const testing::TestCase& test_case) override;
+
+ void WriteTestPartResult(const char* file,
+ int line,
+ testing::TestPartResult::Type type,
+ const std::string& summary,
+ const std::string& message);
+
+ FILE* output_file_;
+ bool open_failed_;
+
+ DISALLOW_COPY_AND_ASSIGN(XmlUnitTestResultPrinter);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_GTEST_XML_UNITTEST_RESULT_PRINTER_H_
diff --git a/chromium/base/test/gtest_xml_util.cc b/chromium/base/test/gtest_xml_util.cc
new file mode 100644
index 00000000000..1bac5a6b1d2
--- /dev/null
+++ b/chromium/base/test/gtest_xml_util.cc
@@ -0,0 +1,235 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/gtest_xml_util.h"
+
+#include <stdint.h>
+
+#include "base/base64.h"
+#include "base/check.h"
+#include "base/files/file_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/gtest_util.h"
+#include "base/test/launcher/test_launcher.h"
+#include "third_party/libxml/chromium/libxml_utils.h"
+#include "third_party/libxml/chromium/xml_reader.h"
+
+namespace base {
+
+namespace {
+
+// This is used for the xml parser to report errors. This assumes the context
+// is a pointer to a std::string where the error message should be appended.
+static void XmlErrorFunc(void *context, const char *message, ...) {
+ va_list args;
+ va_start(args, message);
+ std::string* error = static_cast<std::string*>(context);
+ StringAppendV(error, message, args);
+ va_end(args);
+}
+
+} // namespace
+
+bool ProcessGTestOutput(const base::FilePath& output_file,
+ std::vector<TestResult>* results,
+ bool* crashed) {
+ DCHECK(results);
+
+ std::string xml_contents;
+ if (!ReadFileToString(output_file, &xml_contents))
+ return false;
+
+ // Silence XML errors - otherwise they go to stderr.
+ std::string xml_errors;
+ ScopedXmlErrorFunc error_func(&xml_errors, &XmlErrorFunc);
+
+ XmlReader xml_reader;
+ if (!xml_reader.Load(xml_contents))
+ return false;
+
+ enum {
+ STATE_INIT,
+ STATE_TESTSUITE,
+ STATE_TESTCASE,
+ STATE_TEST_RESULT,
+ STATE_FAILURE,
+ STATE_END,
+ } state = STATE_INIT;
+
+ while (xml_reader.Read()) {
+ xml_reader.SkipToElement();
+ std::string node_name(xml_reader.NodeName());
+
+ switch (state) {
+ case STATE_INIT:
+ if (node_name == "testsuites" && !xml_reader.IsClosingElement())
+ state = STATE_TESTSUITE;
+ else
+ return false;
+ break;
+ case STATE_TESTSUITE:
+ if (node_name == "testsuites" && xml_reader.IsClosingElement())
+ state = STATE_END;
+ else if (node_name == "testsuite" && !xml_reader.IsClosingElement())
+ state = STATE_TESTCASE;
+ else
+ return false;
+ break;
+ case STATE_TESTCASE:
+ if (node_name == "testsuite" && xml_reader.IsClosingElement()) {
+ state = STATE_TESTSUITE;
+ } else if (node_name == "x-teststart" &&
+ !xml_reader.IsClosingElement()) {
+ // This is our custom extension that helps recognize which test was
+ // running when the test binary crashed.
+ TestResult result;
+
+ std::string test_case_name;
+ if (!xml_reader.NodeAttribute("classname", &test_case_name))
+ return false;
+ std::string test_name;
+ if (!xml_reader.NodeAttribute("name", &test_name))
+ return false;
+ result.full_name = FormatFullTestName(test_case_name, test_name);
+
+ result.elapsed_time = TimeDelta();
+
+ // Assume the test crashed - we can correct that later.
+ result.status = TestResult::TEST_CRASH;
+
+ results->push_back(result);
+ } else if (node_name == "testcase" && !xml_reader.IsClosingElement()) {
+ std::string test_status;
+ if (!xml_reader.NodeAttribute("status", &test_status))
+ return false;
+
+ if (test_status != "run" && test_status != "notrun")
+ return false;
+ if (test_status != "run")
+ break;
+
+ TestResult result;
+
+ std::string test_case_name;
+ if (!xml_reader.NodeAttribute("classname", &test_case_name))
+ return false;
+ std::string test_name;
+ if (!xml_reader.NodeAttribute("name", &test_name))
+ return false;
+ result.full_name = test_case_name + "." + test_name;
+
+ std::string test_time_str;
+ if (!xml_reader.NodeAttribute("time", &test_time_str))
+ return false;
+ result.elapsed_time = TimeDelta::FromMicroseconds(
+ static_cast<int64_t>(strtod(test_time_str.c_str(), nullptr) *
+ Time::kMicrosecondsPerSecond));
+
+ result.status = TestResult::TEST_SUCCESS;
+
+ if (!results->empty() &&
+ results->back().full_name == result.full_name &&
+ results->back().status == TestResult::TEST_CRASH) {
+ // Erase the fail-safe "crashed" result - now we know the test did
+ // not crash.
+ results->pop_back();
+ }
+
+ results->push_back(result);
+ } else if (node_name == "failure" && !xml_reader.IsClosingElement()) {
+ std::string failure_message;
+ if (!xml_reader.NodeAttribute("message", &failure_message))
+ return false;
+
+ DCHECK(!results->empty());
+ results->back().status = TestResult::TEST_FAILURE;
+
+ state = STATE_FAILURE;
+ } else if (node_name == "testcase" && xml_reader.IsClosingElement()) {
+ // Deliberately empty.
+ } else if (node_name == "x-test-result-part" &&
+ !xml_reader.IsClosingElement()) {
+ std::string result_type;
+ if (!xml_reader.NodeAttribute("type", &result_type))
+ return false;
+
+ std::string file_name;
+ if (!xml_reader.NodeAttribute("file", &file_name))
+ return false;
+
+ std::string line_number_str;
+ if (!xml_reader.NodeAttribute("line", &line_number_str))
+ return false;
+
+ int line_number;
+ if (!StringToInt(line_number_str, &line_number))
+ return false;
+
+ TestResultPart::Type type;
+ if (!TestResultPart::TypeFromString(result_type, &type))
+ return false;
+
+ TestResultPart test_result_part;
+ test_result_part.type = type;
+ test_result_part.file_name = file_name,
+ test_result_part.line_number = line_number;
+ DCHECK(!results->empty());
+ results->back().test_result_parts.push_back(test_result_part);
+
+ state = STATE_TEST_RESULT;
+ } else {
+ return false;
+ }
+ break;
+ case STATE_TEST_RESULT:
+ if (node_name == "summary" && !xml_reader.IsClosingElement()) {
+ std::string summary;
+ if (!xml_reader.ReadElementContent(&summary))
+ return false;
+
+ if (!Base64Decode(summary, &summary))
+ return false;
+
+ DCHECK(!results->empty());
+ DCHECK(!results->back().test_result_parts.empty());
+ results->back().test_result_parts.back().summary = summary;
+ } else if (node_name == "summary" && xml_reader.IsClosingElement()) {
+ } else if (node_name == "message" && !xml_reader.IsClosingElement()) {
+ std::string message;
+ if (!xml_reader.ReadElementContent(&message))
+ return false;
+
+ if (!Base64Decode(message, &message))
+ return false;
+
+ DCHECK(!results->empty());
+ DCHECK(!results->back().test_result_parts.empty());
+ results->back().test_result_parts.back().message = message;
+ } else if (node_name == "message" && xml_reader.IsClosingElement()) {
+ } else if (node_name == "x-test-result-part" &&
+ xml_reader.IsClosingElement()) {
+ state = STATE_TESTCASE;
+ } else {
+ return false;
+ }
+ break;
+ case STATE_FAILURE:
+ if (node_name == "failure" && xml_reader.IsClosingElement())
+ state = STATE_TESTCASE;
+ else
+ return false;
+ break;
+ case STATE_END:
+ // If we are here and there are still XML elements, the file has wrong
+ // format.
+ return false;
+ }
+ }
+
+ *crashed = (state != STATE_END);
+ return true;
+}
+
+} // namespace base
diff --git a/chromium/base/test/gtest_xml_util.h b/chromium/base/test/gtest_xml_util.h
new file mode 100644
index 00000000000..b023f80da18
--- /dev/null
+++ b/chromium/base/test/gtest_xml_util.h
@@ -0,0 +1,27 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_GTEST_XML_UTIL_H_
+#define BASE_TEST_GTEST_XML_UTIL_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+
+namespace base {
+
+class FilePath;
+struct TestResult;
+
+// Produces a vector of test results based on GTest output file.
+// Returns true iff the output file exists and has been successfully parsed.
+// On successful return |crashed| is set to true if the test results
+// are valid but incomplete.
+bool ProcessGTestOutput(const base::FilePath& output_file,
+ std::vector<TestResult>* results,
+ bool* crashed) WARN_UNUSED_RESULT;
+
+} // namespace base
+
+#endif // BASE_TEST_GTEST_XML_UTIL_H_
diff --git a/chromium/base/test/icu_test_util.cc b/chromium/base/test/icu_test_util.cc
new file mode 100644
index 00000000000..c15a6df9349
--- /dev/null
+++ b/chromium/base/test/icu_test_util.cc
@@ -0,0 +1,49 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/icu_test_util.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/i18n/icu_util.h"
+#include "base/i18n/rtl.h"
+#include "third_party/icu/source/common/unicode/uloc.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+
+namespace base {
+namespace test {
+
+ScopedRestoreICUDefaultLocale::ScopedRestoreICUDefaultLocale()
+ : ScopedRestoreICUDefaultLocale(std::string()) {}
+
+ScopedRestoreICUDefaultLocale::ScopedRestoreICUDefaultLocale(
+ const std::string& locale)
+ : default_locale_(uloc_getDefault()) {
+ if (!locale.empty())
+ i18n::SetICUDefaultLocale(locale.data());
+}
+
+ScopedRestoreICUDefaultLocale::~ScopedRestoreICUDefaultLocale() {
+ i18n::SetICUDefaultLocale(default_locale_.data());
+}
+
+ScopedRestoreDefaultTimezone::ScopedRestoreDefaultTimezone(const char* zoneid) {
+ original_zone_.reset(icu::TimeZone::createDefault());
+ icu::TimeZone::adoptDefault(icu::TimeZone::createTimeZone(zoneid));
+}
+
+ScopedRestoreDefaultTimezone::~ScopedRestoreDefaultTimezone() {
+ icu::TimeZone::adoptDefault(original_zone_.release());
+}
+
+void InitializeICUForTesting() {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kTestDoNotInitializeIcu)) {
+ i18n::AllowMultipleInitializeCallsForTesting();
+ i18n::InitializeICU();
+ }
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/icu_test_util.h b/chromium/base/test/icu_test_util.h
new file mode 100644
index 00000000000..91f44ffbd36
--- /dev/null
+++ b/chromium/base/test/icu_test_util.h
@@ -0,0 +1,59 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_ICU_TEST_UTIL_H_
+#define BASE_TEST_ICU_TEST_UTIL_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "third_party/icu/source/common/unicode/uversion.h"
+
+U_NAMESPACE_BEGIN
+class TimeZone;
+U_NAMESPACE_END
+
+namespace base {
+namespace test {
+
+// In unit tests, prefer ScopedRestoreICUDefaultLocale over
+// calling base::i18n::SetICUDefaultLocale() directly. This scoper makes it
+// harder to accidentally forget to reset the locale.
+class ScopedRestoreICUDefaultLocale {
+ public:
+ ScopedRestoreICUDefaultLocale();
+ explicit ScopedRestoreICUDefaultLocale(const std::string& locale);
+ ~ScopedRestoreICUDefaultLocale();
+
+ private:
+ const std::string default_locale_;
+
+ ScopedRestoreICUDefaultLocale(const ScopedRestoreICUDefaultLocale&) = delete;
+ ScopedRestoreICUDefaultLocale& operator=(
+ const ScopedRestoreICUDefaultLocale&) = delete;
+};
+
+// In unit tests, prefer ScopedRestoreDefaultTimezone over
+// calling icu::TimeZone::adoptDefault() directly. This scoper makes it
+// harder to accidentally forget to reset the locale.
+class ScopedRestoreDefaultTimezone {
+ public:
+ ScopedRestoreDefaultTimezone(const char* zoneid);
+ ~ScopedRestoreDefaultTimezone();
+
+ ScopedRestoreDefaultTimezone(const ScopedRestoreDefaultTimezone&) = delete;
+ ScopedRestoreDefaultTimezone& operator=(const ScopedRestoreDefaultTimezone&) =
+ delete;
+
+ private:
+ std::unique_ptr<icu::TimeZone> original_zone_;
+};
+
+void InitializeICUForTesting();
+
+} // namespace test
+} // namespace base
+
+#endif // BASE_TEST_ICU_TEST_UTIL_H_
diff --git a/chromium/base/test/immediate_crash_test_helper.cc b/chromium/base/test/immediate_crash_test_helper.cc
new file mode 100644
index 00000000000..676a2ba6cdb
--- /dev/null
+++ b/chromium/base/test/immediate_crash_test_helper.cc
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/immediate_crash.h" // nogncheck
+
+#if defined(WIN32)
+#define IMMEDIATE_CRASH_TEST_HELPER_EXPORT __declspec(dllexport)
+#else // defined(WIN32)
+#define IMMEDIATE_CRASH_TEST_HELPER_EXPORT \
+ __attribute__((visibility("default")))
+#endif // defined(WIN32)
+
+extern "C" {
+
+IMMEDIATE_CRASH_TEST_HELPER_EXPORT int TestFunction1(int x, int y) {
+ if (x < 1)
+ IMMEDIATE_CRASH();
+ if (y < 1)
+ IMMEDIATE_CRASH();
+ return x + y;
+}
+
+IMMEDIATE_CRASH_TEST_HELPER_EXPORT int TestFunction2(int x, int y) {
+ if (x < 2)
+ IMMEDIATE_CRASH();
+ if (y < 2)
+ IMMEDIATE_CRASH();
+ return x * y;
+}
+
+} // extern "C"
diff --git a/chromium/base/test/malloc_wrapper.cc b/chromium/base/test/malloc_wrapper.cc
new file mode 100644
index 00000000000..eb280a3eeea
--- /dev/null
+++ b/chromium/base/test/malloc_wrapper.cc
@@ -0,0 +1,11 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "malloc_wrapper.h"
+
+#include <stdlib.h>
+
+void* MallocWrapper(size_t size) {
+ return malloc(size);
+}
diff --git a/chromium/base/test/malloc_wrapper.h b/chromium/base/test/malloc_wrapper.h
new file mode 100644
index 00000000000..e15ea48dc83
--- /dev/null
+++ b/chromium/base/test/malloc_wrapper.h
@@ -0,0 +1,22 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MALLOC_WRAPPER_H_
+#define BASE_TEST_MALLOC_WRAPPER_H_
+
+#include <stddef.h>
+
+// BASE_EXPORT depends on COMPONENT_BUILD.
+// This will always be a separate shared library, so don't use BASE_EXPORT here.
+#if defined(WIN32)
+#define MALLOC_WRAPPER_EXPORT __declspec(dllexport)
+#else
+#define MALLOC_WRAPPER_EXPORT __attribute__((visibility("default")))
+#endif // defined(WIN32)
+
+// Calls malloc directly. Defined as a C function so that the function can be
+// easily referenced by dlsym() without complications from C++ name mangling.
+extern "C" MALLOC_WRAPPER_EXPORT void* MallocWrapper(size_t size);
+
+#endif // BASE_TEST_MALLOC_WRAPPER_H_
diff --git a/chromium/base/test/mock_callback.h b/chromium/base/test/mock_callback.h
new file mode 100644
index 00000000000..24ad8a3b346
--- /dev/null
+++ b/chromium/base/test/mock_callback.h
@@ -0,0 +1,386 @@
+// This file was GENERATED by command:
+// pump.py mock_callback.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Analogous to GMock's built-in MockFunction, but for base::Callback instead of
+// std::function. It takes the full callback type as a parameter, so that it can
+// support both OnceCallback and RepeatingCallback. Furthermore, this file
+// defines convenience typedefs in the form of MockOnceCallback<Signature>,
+// MockRepeatingCallback<Signature>, MockOnceClosure and MockRepeatingClosure.
+//
+// Use:
+// using FooCallback = base::RepeatingCallback<int(std::string)>;
+//
+// TEST(FooTest, RunsCallbackWithBarArgument) {
+// base::MockCallback<FooCallback> callback;
+// EXPECT_CALL(callback, Run("bar")).WillOnce(Return(1));
+// Foo(callback.Get());
+// }
+//
+// Or equivalently:
+//
+// TEST(FooTest, RunsCallbackWithBarArgument) {
+// base::MockRepeatingCallback<int(std::string)> callback;
+// EXPECT_CALL(callback, Run("bar")).WillOnce(Return(1));
+// Foo(callback.Get());
+// }
+//
+//
+// Can be used with StrictMock and NiceMock. Caller must ensure that it outlives
+// any base::Callback obtained from it.
+
+#ifndef BASE_TEST_MOCK_CALLBACK_H_
+#define BASE_TEST_MOCK_CALLBACK_H_
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace base {
+
+// clang-format off
+
+template <typename F>
+class MockCallback;
+
+template <typename Signature>
+using MockOnceCallback = MockCallback<OnceCallback<Signature>>;
+template <typename Signature>
+using MockRepeatingCallback = MockCallback<RepeatingCallback<Signature>>;
+
+using MockOnceClosure = MockCallback<OnceClosure>;
+using MockRepeatingClosure = MockCallback<RepeatingClosure>;
+
+template <typename R>
+class MockCallback<RepeatingCallback<R()>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD0_T(Run, R());
+
+ RepeatingCallback<R()> Get() {
+ return BindRepeating(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R>
+class MockCallback<OnceCallback<R()>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD0_T(Run, R());
+
+ OnceCallback<R()> Get() {
+ return BindOnce(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1>
+class MockCallback<RepeatingCallback<R(A1)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD1_T(Run, R(A1));
+
+ RepeatingCallback<R(A1)> Get() {
+ return BindRepeating(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1>
+class MockCallback<OnceCallback<R(A1)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD1_T(Run, R(A1));
+
+ OnceCallback<R(A1)> Get() {
+ return BindOnce(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2>
+class MockCallback<RepeatingCallback<R(A1, A2)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD2_T(Run, R(A1, A2));
+
+ RepeatingCallback<R(A1, A2)> Get() {
+ return BindRepeating(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2>
+class MockCallback<OnceCallback<R(A1, A2)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD2_T(Run, R(A1, A2));
+
+ OnceCallback<R(A1, A2)> Get() {
+ return BindOnce(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3>
+class MockCallback<RepeatingCallback<R(A1, A2, A3)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD3_T(Run, R(A1, A2, A3));
+
+ RepeatingCallback<R(A1, A2, A3)> Get() {
+ return BindRepeating(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3>
+class MockCallback<OnceCallback<R(A1, A2, A3)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD3_T(Run, R(A1, A2, A3));
+
+ OnceCallback<R(A1, A2, A3)> Get() {
+ return BindOnce(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4>
+class MockCallback<RepeatingCallback<R(A1, A2, A3, A4)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD4_T(Run, R(A1, A2, A3, A4));
+
+ RepeatingCallback<R(A1, A2, A3, A4)> Get() {
+ return BindRepeating(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4>
+class MockCallback<OnceCallback<R(A1, A2, A3, A4)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD4_T(Run, R(A1, A2, A3, A4));
+
+ OnceCallback<R(A1, A2, A3, A4)> Get() {
+ return BindOnce(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5>
+class MockCallback<RepeatingCallback<R(A1, A2, A3, A4, A5)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD5_T(Run, R(A1, A2, A3, A4, A5));
+
+ RepeatingCallback<R(A1, A2, A3, A4, A5)> Get() {
+ return BindRepeating(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5>
+class MockCallback<OnceCallback<R(A1, A2, A3, A4, A5)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD5_T(Run, R(A1, A2, A3, A4, A5));
+
+ OnceCallback<R(A1, A2, A3, A4, A5)> Get() {
+ return BindOnce(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6>
+class MockCallback<RepeatingCallback<R(A1, A2, A3, A4, A5, A6)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD6_T(Run, R(A1, A2, A3, A4, A5, A6));
+
+ RepeatingCallback<R(A1, A2, A3, A4, A5, A6)> Get() {
+ return BindRepeating(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6>
+class MockCallback<OnceCallback<R(A1, A2, A3, A4, A5, A6)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD6_T(Run, R(A1, A2, A3, A4, A5, A6));
+
+ OnceCallback<R(A1, A2, A3, A4, A5, A6)> Get() {
+ return BindOnce(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7>
+class MockCallback<RepeatingCallback<R(A1, A2, A3, A4, A5, A6, A7)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD7_T(Run, R(A1, A2, A3, A4, A5, A6, A7));
+
+ RepeatingCallback<R(A1, A2, A3, A4, A5, A6, A7)> Get() {
+ return BindRepeating(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7>
+class MockCallback<OnceCallback<R(A1, A2, A3, A4, A5, A6, A7)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD7_T(Run, R(A1, A2, A3, A4, A5, A6, A7));
+
+ OnceCallback<R(A1, A2, A3, A4, A5, A6, A7)> Get() {
+ return BindOnce(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8>
+class MockCallback<RepeatingCallback<R(A1, A2, A3, A4, A5, A6, A7, A8)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD8_T(Run, R(A1, A2, A3, A4, A5, A6, A7, A8));
+
+ RepeatingCallback<R(A1, A2, A3, A4, A5, A6, A7, A8)> Get() {
+ return BindRepeating(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8>
+class MockCallback<OnceCallback<R(A1, A2, A3, A4, A5, A6, A7, A8)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD8_T(Run, R(A1, A2, A3, A4, A5, A6, A7, A8));
+
+ OnceCallback<R(A1, A2, A3, A4, A5, A6, A7, A8)> Get() {
+ return BindOnce(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8, typename A9>
+class MockCallback<RepeatingCallback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD9_T(Run, R(A1, A2, A3, A4, A5, A6, A7, A8, A9));
+
+ RepeatingCallback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)> Get() {
+ return BindRepeating(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8, typename A9>
+class MockCallback<OnceCallback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD9_T(Run, R(A1, A2, A3, A4, A5, A6, A7, A8, A9));
+
+ OnceCallback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)> Get() {
+ return BindOnce(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8, typename A9,
+ typename A10>
+class MockCallback<RepeatingCallback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9,
+ A10)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD10_T(Run, R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10));
+
+ RepeatingCallback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> Get() {
+ return BindRepeating(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7, typename A8, typename A9,
+ typename A10>
+class MockCallback<OnceCallback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD10_T(Run, R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10));
+
+ OnceCallback<R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> Get() {
+ return BindOnce(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+// clang-format on
+
+} // namespace base
+
+#endif // BASE_TEST_MOCK_CALLBACK_H_
diff --git a/chromium/base/test/mock_callback.h.pump b/chromium/base/test/mock_callback.h.pump
new file mode 100644
index 00000000000..59155276fd0
--- /dev/null
+++ b/chromium/base/test/mock_callback.h.pump
@@ -0,0 +1,104 @@
+$$ This is a pump file for generating file templates. Pump is a python
+$$ script that is part of the Google Test suite of utilities. Description
+$$ can be found here:
+$$
+$$ https://github.com/google/googletest/blob/master/googletest/docs/PumpManual.md
+$$
+$$ MAX_ARITY controls the number of arguments that MockCallback supports.
+$$ It is choosen to match the number GMock supports.
+$var MAX_ARITY = 10
+$$
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Analogous to GMock's built-in MockFunction, but for base::Callback instead of
+// std::function. It takes the full callback type as a parameter, so that it can
+// support both OnceCallback and RepeatingCallback. Furthermore, this file
+// defines convenience typedefs in the form of MockOnceCallback<Signature>,
+// MockRepeatingCallback<Signature>, MockOnceClosure and MockRepeatingClosure.
+//
+// Use:
+// using FooCallback = base::RepeatingCallback<int(std::string)>;
+//
+// TEST(FooTest, RunsCallbackWithBarArgument) {
+// base::MockCallback<FooCallback> callback;
+// EXPECT_CALL(callback, Run("bar")).WillOnce(Return(1));
+// Foo(callback.Get());
+// }
+//
+// Or equivalently:
+//
+// TEST(FooTest, RunsCallbackWithBarArgument) {
+// base::MockRepeatingCallback<int(std::string)> callback;
+// EXPECT_CALL(callback, Run("bar")).WillOnce(Return(1));
+// Foo(callback.Get());
+// }
+//
+//
+// Can be used with StrictMock and NiceMock. Caller must ensure that it outlives
+// any base::Callback obtained from it.
+
+#ifndef BASE_TEST_MOCK_CALLBACK_H_
+#define BASE_TEST_MOCK_CALLBACK_H_
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace base {
+
+// clang-format off
+
+template <typename F>
+class MockCallback;
+
+template <typename Signature>
+using MockOnceCallback = MockCallback<OnceCallback<Signature>>;
+template <typename Signature>
+using MockRepeatingCallback = MockCallback<RepeatingCallback<Signature>>;
+
+using MockOnceClosure = MockCallback<OnceClosure>;
+using MockRepeatingClosure = MockCallback<RepeatingClosure>;
+
+$range i 0..MAX_ARITY
+$for i [[
+$range j 1..i
+$var run_type = [[R($for j, [[A$j]])]]
+
+template <typename R$for j [[, typename A$j]]>
+class MockCallback<RepeatingCallback<$run_type>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD$(i)_T(Run, $run_type);
+
+ RepeatingCallback<$run_type> Get() {
+ return BindRepeating(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R$for j [[, typename A$j]]>
+class MockCallback<OnceCallback<$run_type>> {
+ public:
+ MockCallback() = default;
+ MOCK_METHOD$(i)_T(Run, $run_type);
+
+ OnceCallback<$run_type> Get() {
+ return BindOnce(&MockCallback::Run, Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+]]
+
+// clang-format on
+
+} // namespace base
+
+#endif // BASE_TEST_MOCK_CALLBACK_H_
diff --git a/chromium/base/test/mock_callback_unittest.cc b/chromium/base/test/mock_callback_unittest.cc
new file mode 100644
index 00000000000..efab2823934
--- /dev/null
+++ b/chromium/base/test/mock_callback_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/mock_callback.h"
+
+#include "base/callback.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::InSequence;
+using testing::Return;
+
+namespace base {
+namespace {
+
+TEST(MockCallbackTest, ZeroArgs) {
+ MockCallback<RepeatingClosure> mock_closure;
+ EXPECT_CALL(mock_closure, Run());
+ mock_closure.Get().Run();
+
+ MockCallback<RepeatingCallback<int()>> mock_int_callback;
+ {
+ InSequence sequence;
+ EXPECT_CALL(mock_int_callback, Run()).WillOnce(Return(42));
+ EXPECT_CALL(mock_int_callback, Run()).WillOnce(Return(88));
+ }
+ EXPECT_EQ(42, mock_int_callback.Get().Run());
+ EXPECT_EQ(88, mock_int_callback.Get().Run());
+}
+
+TEST(MockCallbackTest, WithArgs) {
+ MockCallback<RepeatingCallback<int(int, int)>> mock_two_int_callback;
+ EXPECT_CALL(mock_two_int_callback, Run(1, 2)).WillOnce(Return(42));
+ EXPECT_CALL(mock_two_int_callback, Run(0, 0)).WillRepeatedly(Return(-1));
+ RepeatingCallback<int(int, int)> two_int_callback =
+ mock_two_int_callback.Get();
+ EXPECT_EQ(-1, two_int_callback.Run(0, 0));
+ EXPECT_EQ(42, two_int_callback.Run(1, 2));
+ EXPECT_EQ(-1, two_int_callback.Run(0, 0));
+}
+
+TEST(MockCallbackTest, ZeroArgsOnce) {
+ MockCallback<OnceClosure> mock_closure;
+ EXPECT_CALL(mock_closure, Run());
+ mock_closure.Get().Run();
+
+ MockCallback<OnceCallback<int()>> mock_int_callback;
+ EXPECT_CALL(mock_int_callback, Run()).WillOnce(Return(88));
+ EXPECT_EQ(88, mock_int_callback.Get().Run());
+}
+
+TEST(MockCallbackTest, WithArgsOnce) {
+ MockCallback<OnceCallback<int(int, int)>> mock_two_int_callback;
+ EXPECT_CALL(mock_two_int_callback, Run(1, 2)).WillOnce(Return(42));
+ OnceCallback<int(int, int)> two_int_callback = mock_two_int_callback.Get();
+ EXPECT_EQ(42, std::move(two_int_callback).Run(1, 2));
+}
+
+TEST(MockCallbackTest, Typedefs) {
+ static_assert(std::is_same<MockCallback<RepeatingCallback<int()>>,
+ MockRepeatingCallback<int()>>::value,
+ "Repeating typedef differs for zero args");
+ static_assert(std::is_same<MockCallback<RepeatingCallback<int(int, int)>>,
+ MockRepeatingCallback<int(int, int)>>::value,
+ "Repeating typedef differs for multiple args");
+ static_assert(std::is_same<MockCallback<RepeatingCallback<void()>>,
+ MockRepeatingClosure>::value,
+ "Repeating typedef differs for closure");
+ static_assert(std::is_same<MockCallback<OnceCallback<int()>>,
+ MockOnceCallback<int()>>::value,
+ "Once typedef differs for zero args");
+ static_assert(std::is_same<MockCallback<OnceCallback<int(int, int)>>,
+ MockOnceCallback<int(int, int)>>::value,
+ "Once typedef differs for multiple args");
+ static_assert(std::is_same<MockCallback<RepeatingCallback<void()>>,
+ MockRepeatingClosure>::value,
+ "Once typedef differs for closure");
+}
+
+} // namespace
+} // namespace base
diff --git a/chromium/base/test/mock_chrome_application_mac.mm b/chromium/base/test/mock_chrome_application_mac.mm
new file mode 100644
index 00000000000..2695bc88d4e
--- /dev/null
+++ b/chromium/base/test/mock_chrome_application_mac.mm
@@ -0,0 +1,49 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/mock_chrome_application_mac.h"
+
+#include "base/auto_reset.h"
+#include "base/check.h"
+
+@implementation MockCrApp
+
++ (NSApplication*)sharedApplication {
+ NSApplication* app = [super sharedApplication];
+ DCHECK([app conformsToProtocol:@protocol(CrAppControlProtocol)])
+ << "Existing NSApp (class " << [[app className] UTF8String]
+ << ") does not conform to required protocol.";
+ DCHECK(base::MessagePumpMac::UsingCrApp())
+ << "MessagePumpMac::Create() was called before "
+ << "+[MockCrApp sharedApplication]";
+ return app;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+ base::AutoReset<BOOL> scoper(&_handlingSendEvent, YES);
+ [super sendEvent:event];
+}
+
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
+ _handlingSendEvent = handlingSendEvent;
+}
+
+- (BOOL)isHandlingSendEvent {
+ return _handlingSendEvent;
+}
+
+@end
+
+namespace mock_cr_app {
+
+void RegisterMockCrApp() {
+ [MockCrApp sharedApplication];
+
+ // If there was an invocation to NSApp prior to this method, then the NSApp
+ // will not be a MockCrApp, but will instead be an NSApplication.
+ // This is undesirable and we must enforce that this doesn't happen.
+ CHECK([NSApp isKindOfClass:[MockCrApp class]]);
+}
+
+} // namespace mock_cr_app
diff --git a/chromium/base/test/mock_devices_changed_observer.cc b/chromium/base/test/mock_devices_changed_observer.cc
new file mode 100644
index 00000000000..9fc57cd93e7
--- /dev/null
+++ b/chromium/base/test/mock_devices_changed_observer.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/mock_devices_changed_observer.h"
+
+namespace base {
+
+MockDevicesChangedObserver::MockDevicesChangedObserver() = default;
+
+MockDevicesChangedObserver::~MockDevicesChangedObserver() = default;
+
+} // namespace base
diff --git a/chromium/base/test/mock_devices_changed_observer.h b/chromium/base/test/mock_devices_changed_observer.h
new file mode 100644
index 00000000000..42b8c3f9f24
--- /dev/null
+++ b/chromium/base/test/mock_devices_changed_observer.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
+#define BASE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/system/system_monitor.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace base {
+
+class MockDevicesChangedObserver
+ : public base::SystemMonitor::DevicesChangedObserver {
+ public:
+ MockDevicesChangedObserver();
+ ~MockDevicesChangedObserver() override;
+
+ MOCK_METHOD1(OnDevicesChanged,
+ void(base::SystemMonitor::DeviceType device_type));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockDevicesChangedObserver);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
diff --git a/chromium/base/test/mock_entropy_provider.cc b/chromium/base/test/mock_entropy_provider.cc
new file mode 100644
index 00000000000..f3fd2a481ea
--- /dev/null
+++ b/chromium/base/test/mock_entropy_provider.cc
@@ -0,0 +1,20 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/mock_entropy_provider.h"
+
+namespace base {
+
+MockEntropyProvider::MockEntropyProvider() : entropy_value_(0.5) {}
+MockEntropyProvider::MockEntropyProvider(double entropy_value)
+ : entropy_value_(entropy_value) {}
+MockEntropyProvider::~MockEntropyProvider() = default;
+
+double MockEntropyProvider::GetEntropyForTrial(
+ const std::string& trial_name,
+ uint32_t randomization_seed) const {
+ return entropy_value_;
+}
+
+} // namespace base
diff --git a/chromium/base/test/mock_entropy_provider.h b/chromium/base/test/mock_entropy_provider.h
new file mode 100644
index 00000000000..ca2b4bc8fe0
--- /dev/null
+++ b/chromium/base/test/mock_entropy_provider.h
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MOCK_ENTROPY_PROVIDER_H_
+#define BASE_TEST_MOCK_ENTROPY_PROVIDER_H_
+
+#include <stdint.h>
+
+#include "base/metrics/field_trial.h"
+
+namespace base {
+
+class MockEntropyProvider : public base::FieldTrial::EntropyProvider {
+ public:
+ MockEntropyProvider();
+ explicit MockEntropyProvider(double entropy_value);
+ ~MockEntropyProvider() override;
+
+ // base::FieldTrial::EntropyProvider:
+ double GetEntropyForTrial(const std::string& trial_name,
+ uint32_t randomization_seed) const override;
+
+ private:
+ double entropy_value_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockEntropyProvider);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_MOCK_ENTROPY_PROVIDER_H_
diff --git a/chromium/base/test/mock_log.cc b/chromium/base/test/mock_log.cc
new file mode 100644
index 00000000000..a09000d8ed7
--- /dev/null
+++ b/chromium/base/test/mock_log.cc
@@ -0,0 +1,68 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/mock_log.h"
+
+namespace base {
+namespace test {
+
+// static
+MockLog* MockLog::g_instance_ = nullptr;
+Lock MockLog::g_lock;
+
+MockLog::MockLog() : is_capturing_logs_(false) {
+}
+
+MockLog::~MockLog() {
+ if (is_capturing_logs_) {
+ StopCapturingLogs();
+ }
+}
+
+void MockLog::StartCapturingLogs() {
+ AutoLock scoped_lock(g_lock);
+
+ // We don't use CHECK(), which can generate a new LOG message, and
+ // thus can confuse MockLog objects or other registered
+ // LogSinks.
+ RAW_CHECK(!is_capturing_logs_);
+ RAW_CHECK(!g_instance_);
+
+ is_capturing_logs_ = true;
+ g_instance_ = this;
+ previous_handler_ = logging::GetLogMessageHandler();
+ logging::SetLogMessageHandler(LogMessageHandler);
+}
+
+void MockLog::StopCapturingLogs() {
+ AutoLock scoped_lock(g_lock);
+
+ // We don't use CHECK(), which can generate a new LOG message, and
+ // thus can confuse MockLog objects or other registered
+ // LogSinks.
+ RAW_CHECK(is_capturing_logs_);
+ RAW_CHECK(g_instance_ == this);
+
+ is_capturing_logs_ = false;
+ logging::SetLogMessageHandler(previous_handler_);
+ g_instance_ = nullptr;
+}
+
+// static
+bool MockLog::LogMessageHandler(int severity,
+ const char* file,
+ int line,
+ size_t message_start,
+ const std::string& str) {
+ // gMock guarantees thread-safety for calling a mocked method
+ // (https://github.com/google/googlemock/blob/master/googlemock/docs/CookBook.md#using-google-mock-and-threads)
+ // but we also need to make sure that Start/StopCapturingLogs are synchronized
+ // with LogMessageHandler.
+ AutoLock scoped_lock(g_lock);
+
+ return g_instance_->Log(severity, file, line, message_start, str);
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/mock_log.h b/chromium/base/test/mock_log.h
new file mode 100644
index 00000000000..cda2fcd6259
--- /dev/null
+++ b/chromium/base/test/mock_log.h
@@ -0,0 +1,100 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MOCK_LOG_H_
+#define BASE_TEST_MOCK_LOG_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace base {
+namespace test {
+
+// A MockLog object intercepts LOG() messages issued during its lifespan. Using
+// this together with gMock, it's very easy to test how a piece of code calls
+// LOG(). The typical usage:
+//
+// TEST(FooTest, LogsCorrectly) {
+// MockLog log;
+//
+// // We expect the WARNING "Something bad!" exactly twice.
+// EXPECT_CALL(log, Log(WARNING, _, "Something bad!"))
+// .Times(2);
+//
+// // We allow foo.cc to call LOG(INFO) any number of times.
+// EXPECT_CALL(log, Log(INFO, HasSubstr("/foo.cc"), _))
+// .Times(AnyNumber());
+//
+// log.StartCapturingLogs(); // Call this after done setting expectations.
+// Foo(); // Exercises the code under test.
+// }
+//
+// CAVEAT: base/logging does not allow a thread to call LOG() again when it's
+// already inside a LOG() call. Doing so will cause a deadlock. Therefore,
+// it's the user's responsibility to not call LOG() in an action triggered by
+// MockLog::Log(). You may call RAW_LOG() instead.
+class MockLog {
+ public:
+ // Creates a MockLog object that is not capturing logs. If it were to start
+ // to capture logs, it could be a problem if some other threads already exist
+ // and are logging, as the user hasn't had a chance to set up expectation on
+ // this object yet (calling a mock method before setting the expectation is
+ // UNDEFINED behavior).
+ MockLog();
+
+ // When the object is destructed, it stops intercepting logs.
+ ~MockLog();
+
+ // Starts log capturing if the object isn't already doing so.
+ // Otherwise crashes.
+ void StartCapturingLogs();
+
+ // Stops log capturing if the object is capturing logs. Otherwise crashes.
+ void StopCapturingLogs();
+
+ // Log method is invoked for every log message before it's sent to other log
+ // destinations (if any). The method should return true to signal that it
+ // handled the message and the message should not be sent to other log
+ // destinations.
+ MOCK_METHOD5(Log,
+ bool(int severity,
+ const char* file,
+ int line,
+ size_t message_start,
+ const std::string& str));
+
+ private:
+ // The currently active mock log.
+ static MockLog* g_instance_;
+
+ // Lock protecting access to g_instance_.
+ static Lock g_lock;
+
+ // Static function which is set as the logging message handler.
+ // Called once for each message.
+ static bool LogMessageHandler(int severity,
+ const char* file,
+ int line,
+ size_t message_start,
+ const std::string& str);
+
+ // True if this object is currently capturing logs.
+ bool is_capturing_logs_;
+
+ // The previous handler to restore when the MockLog is destroyed.
+ logging::LogMessageHandlerFunction previous_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockLog);
+};
+
+} // namespace test
+} // namespace base
+
+#endif // BASE_TEST_MOCK_LOG_H_
diff --git a/chromium/base/test/move_only_int.h b/chromium/base/test/move_only_int.h
new file mode 100644
index 00000000000..6e909836240
--- /dev/null
+++ b/chromium/base/test/move_only_int.h
@@ -0,0 +1,68 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MOVE_ONLY_INT_H_
+#define BASE_TEST_MOVE_ONLY_INT_H_
+
+#include "base/macros.h"
+
+namespace base {
+
+// A move-only class that holds an integer. This is designed for testing
+// containers. See also CopyOnlyInt.
+class MoveOnlyInt {
+ public:
+ explicit MoveOnlyInt(int data = 1) : data_(data) {}
+ MoveOnlyInt(MoveOnlyInt&& other) : data_(other.data_) { other.data_ = 0; }
+ ~MoveOnlyInt() { data_ = 0; }
+
+ MoveOnlyInt& operator=(MoveOnlyInt&& other) {
+ data_ = other.data_;
+ other.data_ = 0;
+ return *this;
+ }
+
+ friend bool operator==(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
+ return lhs.data_ == rhs.data_;
+ }
+
+ friend bool operator!=(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
+ return !operator==(lhs, rhs);
+ }
+
+ friend bool operator<(const MoveOnlyInt& lhs, int rhs) {
+ return lhs.data_ < rhs;
+ }
+
+ friend bool operator<(int lhs, const MoveOnlyInt& rhs) {
+ return lhs < rhs.data_;
+ }
+
+ friend bool operator<(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
+ return lhs.data_ < rhs.data_;
+ }
+
+ friend bool operator>(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
+ return rhs < lhs;
+ }
+
+ friend bool operator<=(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
+ return !(rhs < lhs);
+ }
+
+ friend bool operator>=(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
+ return !(lhs < rhs);
+ }
+
+ int data() const { return data_; }
+
+ private:
+ volatile int data_;
+
+ DISALLOW_COPY_AND_ASSIGN(MoveOnlyInt);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_MOVE_ONLY_INT_H_
diff --git a/chromium/base/test/multiprocess_test.cc b/chromium/base/test/multiprocess_test.cc
new file mode 100644
index 00000000000..46556f75732
--- /dev/null
+++ b/chromium/base/test/multiprocess_test.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/multiprocess_test.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
+
+namespace base {
+
+#if !defined(OS_ANDROID)
+Process SpawnMultiProcessTestChild(const std::string& procname,
+ const CommandLine& base_command_line,
+ const LaunchOptions& options) {
+ CommandLine command_line(base_command_line);
+ // TODO(viettrungluu): See comment above |MakeCmdLine()| in the header file.
+ // This is a temporary hack, since |MakeCmdLine()| has to provide a full
+ // command line.
+ if (!command_line.HasSwitch(switches::kTestChildProcess))
+ command_line.AppendSwitchASCII(switches::kTestChildProcess, procname);
+
+ return LaunchProcess(command_line, options);
+}
+
+bool WaitForMultiprocessTestChildExit(const Process& process,
+ TimeDelta timeout,
+ int* exit_code) {
+ return process.WaitForExitWithTimeout(timeout, exit_code);
+}
+
+bool TerminateMultiProcessTestChild(const Process& process,
+ int exit_code,
+ bool wait) {
+ return process.Terminate(exit_code, wait);
+}
+
+#endif // !defined(OS_ANDROID)
+
+CommandLine GetMultiProcessTestChildBaseCommandLine() {
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ CommandLine cmd_line = *CommandLine::ForCurrentProcess();
+ cmd_line.SetProgram(MakeAbsoluteFilePath(cmd_line.GetProgram()));
+ return cmd_line;
+}
+
+// MultiProcessTest ------------------------------------------------------------
+
+MultiProcessTest::MultiProcessTest() = default;
+
+Process MultiProcessTest::SpawnChild(const std::string& procname) {
+ LaunchOptions options;
+#if defined(OS_WIN)
+ options.start_hidden = true;
+#endif
+ return SpawnChildWithOptions(procname, options);
+}
+
+Process MultiProcessTest::SpawnChildWithOptions(const std::string& procname,
+ const LaunchOptions& options) {
+ return SpawnMultiProcessTestChild(procname, MakeCmdLine(procname), options);
+}
+
+CommandLine MultiProcessTest::MakeCmdLine(const std::string& procname) {
+ CommandLine command_line = GetMultiProcessTestChildBaseCommandLine();
+ command_line.AppendSwitchASCII(switches::kTestChildProcess, procname);
+ return command_line;
+}
+
+} // namespace base
diff --git a/chromium/base/test/multiprocess_test.h b/chromium/base/test/multiprocess_test.h
new file mode 100644
index 00000000000..52c35e02ef2
--- /dev/null
+++ b/chromium/base/test/multiprocess_test.h
@@ -0,0 +1,151 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MULTIPROCESS_TEST_H_
+#define BASE_TEST_MULTIPROCESS_TEST_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/process/launch.h"
+#include "base/process/process.h"
+#include "build/build_config.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+class CommandLine;
+
+// Helpers to spawn a child for a multiprocess test and execute a designated
+// function. Use these when you already have another base class for your test
+// fixture, but you want (some) of your tests to be multiprocess (otherwise you
+// may just want to derive your fixture from |MultiProcessTest|, below).
+//
+// Use these helpers as follows:
+//
+// TEST_F(MyTest, ATest) {
+// CommandLine command_line(
+// base::GetMultiProcessTestChildBaseCommandLine());
+// // Maybe add our own switches to |command_line|....
+//
+// LaunchOptions options;
+// // Maybe set some options (e.g., |start_hidden| on Windows)....
+//
+// // Start a child process and run |a_test_func|.
+// base::Process test_child_process =
+// base::SpawnMultiProcessTestChild("a_test_func", command_line,
+// options);
+//
+// // Do stuff involving |test_child_process| and the child process....
+//
+// int rv = -1;
+// ASSERT_TRUE(base::WaitForMultiprocessTestChildExit(test_child_process,
+// TestTimeouts::action_timeout(), &rv));
+// EXPECT_EQ(0, rv);
+// }
+//
+// // Note: |MULTIPROCESS_TEST_MAIN()| is defined in
+// // testing/multiprocess_func_list.h.
+// MULTIPROCESS_TEST_MAIN(a_test_func) {
+// // Code here runs in a child process....
+// return 0;
+// }
+//
+// If you need to terminate the child process, use the
+// TerminateMultiProcessTestChild method to ensure that test will work on
+// Android.
+
+// Spawns a child process and executes the function |procname| declared using
+// |MULTIPROCESS_TEST_MAIN()| or |MULTIPROCESS_TEST_MAIN_WITH_SETUP()|.
+// |command_line| should be as provided by
+// |GetMultiProcessTestChildBaseCommandLine()| (below), possibly with arguments
+// added. Note: On Windows, you probably want to set |options.start_hidden|.
+Process SpawnMultiProcessTestChild(const std::string& procname,
+ const CommandLine& command_line,
+ const LaunchOptions& options);
+
+// Gets the base command line for |SpawnMultiProcessTestChild()|. To this, you
+// may add any flags needed for your child process.
+CommandLine GetMultiProcessTestChildBaseCommandLine();
+
+// Waits for the child process to exit. Returns true if the process exited
+// within |timeout| and sets |exit_code| if non null.
+bool WaitForMultiprocessTestChildExit(const Process& process,
+ TimeDelta timeout,
+ int* exit_code);
+
+// Terminates |process| with |exit_code|. If |wait| is true, this call blocks
+// until the process actually terminates.
+bool TerminateMultiProcessTestChild(const Process& process,
+ int exit_code,
+ bool wait);
+
+#if defined(OS_ANDROID)
+// Returns whether the child process exited cleanly from the main runloop.
+bool MultiProcessTestChildHasCleanExit(const Process& process);
+#endif
+
+// MultiProcessTest ------------------------------------------------------------
+
+// A MultiProcessTest is a test class which makes it easier to
+// write a test which requires code running out of process.
+//
+// To create a multiprocess test simply follow these steps:
+//
+// 1) Derive your test from MultiProcessTest. Example:
+//
+// class MyTest : public MultiProcessTest {
+// };
+//
+// TEST_F(MyTest, TestCaseName) {
+// ...
+// }
+//
+// 2) Create a mainline function for the child processes and include
+// testing/multiprocess_func_list.h.
+// See the declaration of the MULTIPROCESS_TEST_MAIN macro
+// in that file for an example.
+// 3) Call SpawnChild("foo"), where "foo" is the name of
+// the function you wish to run in the child processes.
+// That's it!
+class MultiProcessTest : public PlatformTest {
+ public:
+ MultiProcessTest();
+
+ protected:
+ // Run a child process.
+ // 'procname' is the name of a function which the child will
+ // execute. It must be exported from this library in order to
+ // run.
+ //
+ // Example signature:
+ // extern "C" int __declspec(dllexport) FooBar() {
+ // // do client work here
+ // }
+ //
+ // Returns the child process.
+ Process SpawnChild(const std::string& procname);
+
+ // Run a child process using the given launch options.
+ //
+ // Note: On Windows, you probably want to set |options.start_hidden|.
+ Process SpawnChildWithOptions(const std::string& procname,
+ const LaunchOptions& options);
+
+ // Set up the command line used to spawn the child process.
+ // Override this to add things to the command line (calling this first in the
+ // override).
+ // Note that currently some tests rely on this providing a full command line,
+ // which they then use directly with |LaunchProcess()|.
+ // TODO(viettrungluu): Remove this and add a virtual
+ // |ModifyChildCommandLine()|; make the two divergent uses more sane.
+ virtual CommandLine MakeCmdLine(const std::string& procname);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MultiProcessTest);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_MULTIPROCESS_TEST_H_
diff --git a/chromium/base/test/multiprocess_test_android.cc b/chromium/base/test/multiprocess_test_android.cc
new file mode 100644
index 00000000000..f3e3ea34bca
--- /dev/null
+++ b/chromium/base/test/multiprocess_test_android.cc
@@ -0,0 +1,94 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/multiprocess_test.h"
+
+#include <string.h>
+#include <vector>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/base_switches.h"
+#include "base/check.h"
+#include "base/command_line.h"
+#include "base/test/test_support_jni_headers/MainReturnCodeResult_jni.h"
+#include "base/test/test_support_jni_headers/MultiprocessTestClientLauncher_jni.h"
+
+namespace base {
+
+// A very basic implementation for Android. On Android tests can run in an APK
+// and we don't have an executable to exec*. This implementation does the bare
+// minimum to execute the method specified by procname (in the child process).
+// - All options except |fds_to_remap| are ignored.
+//
+// NOTE: This MUST NOT run on the main thread of the NativeTest application.
+Process SpawnMultiProcessTestChild(const std::string& procname,
+ const CommandLine& base_command_line,
+ const LaunchOptions& options) {
+ JNIEnv* env = android::AttachCurrentThread();
+ DCHECK(env);
+
+ std::vector<int> fd_keys;
+ std::vector<int> fd_fds;
+ for (auto& iter : options.fds_to_remap) {
+ fd_keys.push_back(iter.second);
+ fd_fds.push_back(iter.first);
+ }
+
+ android::ScopedJavaLocalRef<jobjectArray> fds =
+ android::Java_MultiprocessTestClientLauncher_makeFdInfoArray(
+ env, base::android::ToJavaIntArray(env, fd_keys),
+ base::android::ToJavaIntArray(env, fd_fds));
+
+ CommandLine command_line(base_command_line);
+ if (!command_line.HasSwitch(switches::kTestChildProcess)) {
+ command_line.AppendSwitchASCII(switches::kTestChildProcess, procname);
+ }
+
+ android::ScopedJavaLocalRef<jobjectArray> j_argv =
+ android::ToJavaArrayOfStrings(env, command_line.argv());
+ jint pid = android::Java_MultiprocessTestClientLauncher_launchClient(
+ env, j_argv, fds);
+ return Process(pid);
+}
+
+bool WaitForMultiprocessTestChildExit(const Process& process,
+ TimeDelta timeout,
+ int* exit_code) {
+ JNIEnv* env = android::AttachCurrentThread();
+ DCHECK(env);
+
+ base::android::ScopedJavaLocalRef<jobject> result_code =
+ android::Java_MultiprocessTestClientLauncher_waitForMainToReturn(
+ env, process.Pid(), static_cast<int32_t>(timeout.InMilliseconds()));
+ if (result_code.is_null() ||
+ Java_MainReturnCodeResult_hasTimedOut(env, result_code)) {
+ return false;
+ }
+ if (exit_code) {
+ *exit_code = Java_MainReturnCodeResult_getReturnCode(env, result_code);
+ }
+ return true;
+}
+
+bool TerminateMultiProcessTestChild(const Process& process,
+ int exit_code,
+ bool wait) {
+ JNIEnv* env = android::AttachCurrentThread();
+ DCHECK(env);
+
+ return android::Java_MultiprocessTestClientLauncher_terminate(
+ env, process.Pid(), exit_code, wait);
+}
+
+bool MultiProcessTestChildHasCleanExit(const Process& process) {
+ JNIEnv* env = android::AttachCurrentThread();
+ DCHECK(env);
+
+ return android::Java_MultiprocessTestClientLauncher_hasCleanExit(
+ env, process.Pid());
+}
+
+} // namespace base
diff --git a/chromium/base/test/native_library_test_utils.cc b/chromium/base/test/native_library_test_utils.cc
new file mode 100644
index 00000000000..adcb1b01e90
--- /dev/null
+++ b/chromium/base/test/native_library_test_utils.cc
@@ -0,0 +1,19 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/native_library_test_utils.h"
+
+namespace {
+
+int g_static_value = 0;
+
+} // namespace
+
+extern "C" {
+
+int g_native_library_exported_value = 0;
+
+int NativeLibraryTestIncrement() { return ++g_static_value; }
+
+} // extern "C"
diff --git a/chromium/base/test/native_library_test_utils.h b/chromium/base/test/native_library_test_utils.h
new file mode 100644
index 00000000000..e26fd1a04e6
--- /dev/null
+++ b/chromium/base/test/native_library_test_utils.h
@@ -0,0 +1,26 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_NATIVE_LIBRARY_TEST_UTILS_H_
+#define BASE_TEST_NATIVE_LIBRARY_TEST_UTILS_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#define NATIVE_LIBRARY_TEST_ALWAYS_EXPORT __declspec(dllexport)
+#else
+#define NATIVE_LIBRARY_TEST_ALWAYS_EXPORT __attribute__((visibility("default")))
+#endif
+
+extern "C" {
+
+extern NATIVE_LIBRARY_TEST_ALWAYS_EXPORT int g_native_library_exported_value;
+
+// A function which increments an internal counter value and returns its value.
+// The first call returns 1, then 2, etc.
+NATIVE_LIBRARY_TEST_ALWAYS_EXPORT int NativeLibraryTestIncrement();
+
+} // extern "C"
+
+#endif // BASE_TEST_NATIVE_LIBRARY_TEST_UTILS_H_
diff --git a/chromium/base/test/null_task_runner.cc b/chromium/base/test/null_task_runner.cc
new file mode 100644
index 00000000000..dfa26fa313c
--- /dev/null
+++ b/chromium/base/test/null_task_runner.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/null_task_runner.h"
+
+namespace base {
+
+NullTaskRunner::NullTaskRunner() = default;
+
+NullTaskRunner::~NullTaskRunner() = default;
+
+bool NullTaskRunner::PostDelayedTask(const Location& from_here,
+ OnceClosure task,
+ base::TimeDelta delay) {
+ return false;
+}
+
+bool NullTaskRunner::PostNonNestableDelayedTask(const Location& from_here,
+ OnceClosure task,
+ base::TimeDelta delay) {
+ return false;
+}
+
+bool NullTaskRunner::RunsTasksInCurrentSequence() const {
+ return true;
+}
+
+} // namespace base
diff --git a/chromium/base/test/null_task_runner.h b/chromium/base/test/null_task_runner.h
new file mode 100644
index 00000000000..8ed339526d0
--- /dev/null
+++ b/chromium/base/test/null_task_runner.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_NULL_TASK_RUNNER_H_
+#define BASE_TEST_NULL_TASK_RUNNER_H_
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+// ATTENTION: Prefer SingleThreadTaskEnvironment or TaskEnvironment w/
+// ThreadPoolExecutionMode::QUEUED over this class. A NullTaskRunner might seem
+// appealing, but not running tasks is under-testing the potential side-effects
+// of the code under tests. All tests should be okay if tasks born from their
+// actions are run or deleted at a later point.
+//
+// Helper class for tests that need to provide an implementation of a
+// *TaskRunner class but don't actually care about tasks being run.
+class NullTaskRunner : public base::SingleThreadTaskRunner {
+ public:
+ NullTaskRunner();
+
+ bool PostDelayedTask(const Location& from_here,
+ base::OnceClosure task,
+ base::TimeDelta delay) override;
+ bool PostNonNestableDelayedTask(const Location& from_here,
+ base::OnceClosure task,
+ base::TimeDelta delay) override;
+ // Always returns true to avoid triggering DCHECKs.
+ bool RunsTasksInCurrentSequence() const override;
+
+ protected:
+ ~NullTaskRunner() override;
+
+ DISALLOW_COPY_AND_ASSIGN(NullTaskRunner);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_NULL_TASK_RUNNER_H_
diff --git a/chromium/base/test/perf_log.cc b/chromium/base/test/perf_log.cc
new file mode 100644
index 00000000000..e275ac0922f
--- /dev/null
+++ b/chromium/base/test/perf_log.cc
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/perf_log.h"
+
+#include "base/files/file_util.h"
+#include "base/notreached.h"
+
+namespace base {
+
+static FILE* perf_log_file = nullptr;
+
+bool InitPerfLog(const FilePath& log_file) {
+ if (perf_log_file) {
+ // trying to initialize twice
+ NOTREACHED();
+ return false;
+ }
+
+ perf_log_file = OpenFile(log_file, "w");
+ return perf_log_file != nullptr;
+}
+
+void FinalizePerfLog() {
+ if (!perf_log_file) {
+ // trying to cleanup without initializing
+ NOTREACHED();
+ return;
+ }
+ base::CloseFile(perf_log_file);
+}
+
+void LogPerfResult(const char* test_name, double value, const char* units) {
+ if (!perf_log_file) {
+ NOTREACHED();
+ return;
+ }
+
+ fprintf(perf_log_file, "%s\t%g\t%s\n", test_name, value, units);
+ printf("%s\t%g\t%s\n", test_name, value, units);
+ fflush(stdout);
+}
+
+} // namespace base
diff --git a/chromium/base/test/perf_log.h b/chromium/base/test/perf_log.h
new file mode 100644
index 00000000000..5d6ed9f8ba4
--- /dev/null
+++ b/chromium/base/test/perf_log.h
@@ -0,0 +1,24 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_PERF_LOG_H_
+#define BASE_TEST_PERF_LOG_H_
+
+namespace base {
+
+class FilePath;
+
+// Initializes and finalizes the perf log. These functions should be
+// called at the beginning and end (respectively) of running all the
+// performance tests. The init function returns true on success.
+bool InitPerfLog(const FilePath& log_path);
+void FinalizePerfLog();
+
+// Writes to the perf result log the given 'value' resulting from the
+// named 'test'. The units are to aid in reading the log by people.
+void LogPerfResult(const char* test_name, double value, const char* units);
+
+} // namespace base
+
+#endif // BASE_TEST_PERF_LOG_H_
diff --git a/chromium/base/test/perf_test_suite.cc b/chromium/base/test/perf_test_suite.cc
new file mode 100644
index 00000000000..2e2cdbb751e
--- /dev/null
+++ b/chromium/base/test/perf_test_suite.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/perf_test_suite.h"
+
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/process/launch.h"
+#include "base/strings/string_util.h"
+#include "base/test/perf_log.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+PerfTestSuite::PerfTestSuite(int argc, char** argv) : TestSuite(argc, argv) {}
+
+void PerfTestSuite::Initialize() {
+ TestSuite::Initialize();
+
+ // Initialize the perf timer log
+ FilePath log_path =
+ CommandLine::ForCurrentProcess()->GetSwitchValuePath("log-file");
+ if (log_path.empty()) {
+ PathService::Get(FILE_EXE, &log_path);
+#if defined(OS_ANDROID) || defined(OS_FUCHSIA)
+ base::FilePath tmp_dir;
+ PathService::Get(base::DIR_CACHE, &tmp_dir);
+ log_path = tmp_dir.Append(log_path.BaseName());
+#endif
+ log_path = log_path.ReplaceExtension(FILE_PATH_LITERAL("log"));
+ log_path = log_path.InsertBeforeExtension(FILE_PATH_LITERAL("_perf"));
+ }
+ ASSERT_TRUE(InitPerfLog(log_path));
+
+ // Raise to high priority to have more precise measurements. Since we don't
+ // aim at 1% precision, it is not necessary to run at realtime level.
+ if (!debug::BeingDebugged())
+ RaiseProcessToHighPriority();
+}
+
+void PerfTestSuite::Shutdown() {
+ TestSuite::Shutdown();
+ FinalizePerfLog();
+}
+
+} // namespace base
diff --git a/chromium/base/test/perf_test_suite.h b/chromium/base/test/perf_test_suite.h
new file mode 100644
index 00000000000..52528f0ac45
--- /dev/null
+++ b/chromium/base/test/perf_test_suite.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_PERF_TEST_SUITE_H_
+#define BASE_TEST_PERF_TEST_SUITE_H_
+
+#include "base/test/test_suite.h"
+
+namespace base {
+
+class PerfTestSuite : public TestSuite {
+ public:
+ PerfTestSuite(int argc, char** argv);
+
+ void Initialize() override;
+ void Shutdown() override;
+};
+
+} // namespace base
+
+#endif // BASE_TEST_PERF_TEST_SUITE_H_
diff --git a/chromium/base/test/perf_time_logger.cc b/chromium/base/test/perf_time_logger.cc
new file mode 100644
index 00000000000..c05ba51b7d8
--- /dev/null
+++ b/chromium/base/test/perf_time_logger.cc
@@ -0,0 +1,27 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/perf_time_logger.h"
+
+#include "base/test/perf_log.h"
+
+namespace base {
+
+PerfTimeLogger::PerfTimeLogger(const char* test_name)
+ : logged_(false), test_name_(test_name) {}
+
+PerfTimeLogger::~PerfTimeLogger() {
+ if (!logged_)
+ Done();
+}
+
+void PerfTimeLogger::Done() {
+ // we use a floating-point millisecond value because it is more
+ // intuitive than microseconds and we want more precision than
+ // integer milliseconds
+ LogPerfResult(test_name_.c_str(), timer_.Elapsed().InMillisecondsF(), "ms");
+ logged_ = true;
+}
+
+} // namespace base
diff --git a/chromium/base/test/perf_time_logger.h b/chromium/base/test/perf_time_logger.h
new file mode 100644
index 00000000000..a5f3e8a70c3
--- /dev/null
+++ b/chromium/base/test/perf_time_logger.h
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_PERF_TIME_LOGGER_H_
+#define BASE_TEST_PERF_TIME_LOGGER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/timer/elapsed_timer.h"
+
+namespace base {
+
+// Automates calling LogPerfResult for the common case where you want
+// to measure the time that something took. Call Done() when the test
+// is complete if you do extra work after the test or there are stack
+// objects with potentially expensive constructors. Otherwise, this
+// class with automatically log on destruction.
+class PerfTimeLogger {
+ public:
+ explicit PerfTimeLogger(const char* test_name);
+ ~PerfTimeLogger();
+
+ void Done();
+
+ private:
+ bool logged_;
+ std::string test_name_;
+ ElapsedTimer timer_;
+
+ DISALLOW_COPY_AND_ASSIGN(PerfTimeLogger);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_PERF_TIME_LOGGER_H_
diff --git a/chromium/base/test/power_monitor_test_base.cc b/chromium/base/test/power_monitor_test_base.cc
new file mode 100644
index 00000000000..f37fb579688
--- /dev/null
+++ b/chromium/base/test/power_monitor_test_base.cc
@@ -0,0 +1,65 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/power_monitor_test_base.h"
+
+#include "base/message_loop/message_loop_current.h"
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_source.h"
+#include "base/run_loop.h"
+
+namespace base {
+
+PowerMonitorTestSource::PowerMonitorTestSource()
+ : test_on_battery_power_(false) {
+ DCHECK(MessageLoopCurrent::Get())
+ << "PowerMonitorTestSource requires a MessageLoop.";
+}
+
+PowerMonitorTestSource::~PowerMonitorTestSource() = default;
+
+void PowerMonitorTestSource::GeneratePowerStateEvent(bool on_battery_power) {
+ test_on_battery_power_ = on_battery_power;
+ ProcessPowerEvent(POWER_STATE_EVENT);
+ RunLoop().RunUntilIdle();
+}
+
+void PowerMonitorTestSource::GenerateSuspendEvent() {
+ ProcessPowerEvent(SUSPEND_EVENT);
+ RunLoop().RunUntilIdle();
+}
+
+void PowerMonitorTestSource::GenerateResumeEvent() {
+ ProcessPowerEvent(RESUME_EVENT);
+ RunLoop().RunUntilIdle();
+}
+
+bool PowerMonitorTestSource::IsOnBatteryPowerImpl() {
+ return test_on_battery_power_;
+}
+
+PowerMonitorTestObserver::PowerMonitorTestObserver()
+ : last_power_state_(false),
+ power_state_changes_(0),
+ suspends_(0),
+ resumes_(0) {
+}
+
+PowerMonitorTestObserver::~PowerMonitorTestObserver() = default;
+
+// PowerObserver callbacks.
+void PowerMonitorTestObserver::OnPowerStateChange(bool on_battery_power) {
+ last_power_state_ = on_battery_power;
+ power_state_changes_++;
+}
+
+void PowerMonitorTestObserver::OnSuspend() {
+ suspends_++;
+}
+
+void PowerMonitorTestObserver::OnResume() {
+ resumes_++;
+}
+
+} // namespace base
diff --git a/chromium/base/test/power_monitor_test_base.h b/chromium/base/test/power_monitor_test_base.h
new file mode 100644
index 00000000000..3086bb87496
--- /dev/null
+++ b/chromium/base/test/power_monitor_test_base.h
@@ -0,0 +1,53 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_POWER_MONITOR_TEST_BASE_H_
+#define BASE_TEST_POWER_MONITOR_TEST_BASE_H_
+
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_source.h"
+
+namespace base {
+
+class PowerMonitorTestSource : public PowerMonitorSource {
+ public:
+ PowerMonitorTestSource();
+ ~PowerMonitorTestSource() override;
+
+ void GeneratePowerStateEvent(bool on_battery_power);
+ void GenerateSuspendEvent();
+ void GenerateResumeEvent();
+
+ protected:
+ bool IsOnBatteryPowerImpl() override;
+
+ bool test_on_battery_power_;
+};
+
+class PowerMonitorTestObserver : public PowerObserver {
+ public:
+ PowerMonitorTestObserver();
+ ~PowerMonitorTestObserver() override;
+
+ // PowerObserver callbacks.
+ void OnPowerStateChange(bool on_battery_power) override;
+ void OnSuspend() override;
+ void OnResume() override;
+
+ // Test status counts.
+ bool last_power_state() const { return last_power_state_; }
+ int power_state_changes() const { return power_state_changes_; }
+ int suspends() const { return suspends_; }
+ int resumes() const { return resumes_; }
+
+ private:
+ bool last_power_state_; // Last power state we were notified of.
+ int power_state_changes_; // Count of OnPowerStateChange notifications.
+ int suspends_; // Count of OnSuspend notifications.
+ int resumes_; // Count of OnResume notifications.
+};
+
+} // namespace base
+
+#endif // BASE_TEST_POWER_MONITOR_TEST_BASE_H_
diff --git a/chromium/base/test/reached_code_profiler_android.cc b/chromium/base/test/reached_code_profiler_android.cc
new file mode 100644
index 00000000000..cfedc6b37a8
--- /dev/null
+++ b/chromium/base/test/reached_code_profiler_android.cc
@@ -0,0 +1,25 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_android.h"
+#include "base/android/reached_code_profiler.h"
+#include "base/test/test_support_jni_headers/ReachedCodeProfiler_jni.h"
+
+// This file provides functions to query the state of the reached code profiler
+// from Java. It's used only for tests.
+namespace base {
+namespace android {
+
+static jboolean JNI_ReachedCodeProfiler_IsReachedCodeProfilerEnabled(
+ JNIEnv* env) {
+ return IsReachedCodeProfilerEnabled();
+}
+
+static jboolean JNI_ReachedCodeProfiler_IsReachedCodeProfilerSupported(
+ JNIEnv* env) {
+ return IsReachedCodeProfilerSupported();
+}
+
+} // namespace android
+} // namespace base
diff --git a/chromium/base/test/run_all_base_unittests.cc b/chromium/base/test/run_all_base_unittests.cc
new file mode 100644
index 00000000000..aa7a9bf5bb0
--- /dev/null
+++ b/chromium/base/test/run_all_base_unittests.cc
@@ -0,0 +1,15 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "build/build_config.h"
+
+int main(int argc, char** argv) {
+ base::TestSuite test_suite(argc, argv);
+ return base::LaunchUnitTests(
+ argc, argv,
+ base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/chromium/base/test/run_all_perftests.cc b/chromium/base/test/run_all_perftests.cc
new file mode 100644
index 00000000000..6e38109376a
--- /dev/null
+++ b/chromium/base/test/run_all_perftests.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/perf_test_suite.h"
+
+int main(int argc, char** argv) {
+ return base::PerfTestSuite(argc, argv).Run();
+}
diff --git a/chromium/base/test/run_all_unittests.cc b/chromium/base/test/run_all_unittests.cc
new file mode 100644
index 00000000000..0ad84ed53d2
--- /dev/null
+++ b/chromium/base/test/run_all_unittests.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "build/build_config.h"
+
+int main(int argc, char** argv) {
+ base::TestSuite test_suite(argc, argv);
+ return base::LaunchUnitTests(
+ argc, argv,
+ base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/chromium/base/test/scoped_command_line.cc b/chromium/base/test/scoped_command_line.cc
new file mode 100644
index 00000000000..c74d243f448
--- /dev/null
+++ b/chromium/base/test/scoped_command_line.cc
@@ -0,0 +1,22 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_command_line.h"
+
+namespace base {
+namespace test {
+
+ScopedCommandLine::ScopedCommandLine()
+ : original_command_line_(*base::CommandLine::ForCurrentProcess()) {}
+
+ScopedCommandLine::~ScopedCommandLine() {
+ *base::CommandLine::ForCurrentProcess() = original_command_line_;
+}
+
+CommandLine* ScopedCommandLine::GetProcessCommandLine() {
+ return base::CommandLine::ForCurrentProcess();
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/scoped_command_line.h b/chromium/base/test/scoped_command_line.h
new file mode 100644
index 00000000000..dea0c6ac1e6
--- /dev/null
+++ b/chromium/base/test/scoped_command_line.h
@@ -0,0 +1,34 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_COMMAND_LINE_H_
+#define BASE_TEST_SCOPED_COMMAND_LINE_H_
+
+#include "base/command_line.h"
+
+namespace base {
+namespace test {
+
+// Helper class to restore the original command line at the end of the scope.
+// NOTE: In most unit tests, the command line is automatically restored per
+// test, so this class is not necessary if the command line applies to
+// the entire single test.
+class ScopedCommandLine final {
+ public:
+ ScopedCommandLine();
+ ~ScopedCommandLine();
+
+ // Gets the command line for the current process.
+ // NOTE: Do not name this GetCommandLine as this will conflict with Windows's
+ // GetCommandLine and get renamed to GetCommandLineW.
+ CommandLine* GetProcessCommandLine();
+
+ private:
+ const CommandLine original_command_line_;
+};
+
+} // namespace test
+} // namespace base
+
+#endif // BASE_TEST_SCOPED_COMMAND_LINE_H_
diff --git a/chromium/base/test/scoped_environment_variable_override.cc b/chromium/base/test/scoped_environment_variable_override.cc
new file mode 100644
index 00000000000..4b7b3871415
--- /dev/null
+++ b/chromium/base/test/scoped_environment_variable_override.cc
@@ -0,0 +1,33 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_environment_variable_override.h"
+
+#include "base/environment.h"
+
+namespace base {
+namespace test {
+
+ScopedEnvironmentVariableOverride::ScopedEnvironmentVariableOverride(
+ const std::string& variable_name,
+ const std::string& value)
+ : environment_(Environment::Create()),
+ variable_name_(variable_name),
+ overridden_(false),
+ was_set_(false) {
+ was_set_ = environment_->GetVar(variable_name, &old_value_);
+ overridden_ = environment_->SetVar(variable_name, value);
+}
+
+ScopedEnvironmentVariableOverride::~ScopedEnvironmentVariableOverride() {
+ if (overridden_) {
+ if (was_set_)
+ environment_->SetVar(variable_name_, old_value_);
+ else
+ environment_->UnSetVar(variable_name_);
+ }
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/scoped_environment_variable_override.h b/chromium/base/test/scoped_environment_variable_override.h
new file mode 100644
index 00000000000..b05b5f9a405
--- /dev/null
+++ b/chromium/base/test/scoped_environment_variable_override.h
@@ -0,0 +1,40 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_ENVIRONMENT_VARIABLE_OVERRIDE_H_
+#define BASE_TEST_SCOPED_ENVIRONMENT_VARIABLE_OVERRIDE_H_
+
+#include <memory>
+#include <string>
+
+namespace base {
+
+class Environment;
+
+namespace test {
+
+// Helper class to override |variable_name| environment variable to |value| for
+// the lifetime of this class. Upon destruction, the previous value is restored.
+class ScopedEnvironmentVariableOverride final {
+ public:
+ ScopedEnvironmentVariableOverride(const std::string& variable_name,
+ const std::string& value);
+ ~ScopedEnvironmentVariableOverride();
+
+ base::Environment* GetEnv() { return environment_.get(); }
+ bool IsOverridden() { return overridden_; }
+ bool WasSet() { return was_set_; }
+
+ private:
+ std::unique_ptr<Environment> environment_;
+ std::string variable_name_;
+ bool overridden_;
+ bool was_set_;
+ std::string old_value_;
+};
+
+} // namespace test
+} // namespace base
+
+#endif // BASE_TEST_SCOPED_ENVIRONMENT_VARIABLE_OVERRIDE_H_
diff --git a/chromium/base/test/scoped_feature_list.cc b/chromium/base/test/scoped_feature_list.cc
new file mode 100644
index 00000000000..0e5afdb2e36
--- /dev/null
+++ b/chromium/base/test/scoped_feature_list.cc
@@ -0,0 +1,301 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_feature_list.h"
+
+#include <algorithm>
+#include <utility>
+#include <vector>
+
+#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial_param_associator.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/test/mock_entropy_provider.h"
+
+namespace base {
+namespace test {
+
+namespace {
+
+constexpr char kTrialGroup[] = "scoped_feature_list_trial_group";
+
+std::vector<StringPiece> GetFeatureVector(
+ const std::vector<Feature>& features) {
+ std::vector<StringPiece> output;
+ for (const Feature& feature : features) {
+ output.push_back(feature.name);
+ }
+
+ return output;
+}
+
+std::vector<StringPiece> GetFeatureVectorFromFeaturesAndParams(
+ const std::vector<ScopedFeatureList::FeatureAndParams>&
+ features_and_params) {
+ std::vector<StringPiece> output;
+ for (const auto& entry : features_and_params) {
+ output.push_back(entry.feature.name);
+ }
+
+ return output;
+}
+
+// Extracts a feature name from a feature state string. For example, given
+// the input "*MyLovelyFeature<SomeFieldTrial", returns "MyLovelyFeature".
+StringPiece GetFeatureName(StringPiece feature) {
+ StringPiece feature_name = feature;
+
+ // Remove default info.
+ if (feature_name.starts_with("*"))
+ feature_name = feature_name.substr(1);
+
+ // Remove field_trial info.
+ std::size_t index = feature_name.find("<");
+ if (index != std::string::npos)
+ feature_name = feature_name.substr(0, index);
+
+ return feature_name;
+}
+
+struct Features {
+ std::vector<StringPiece> enabled_feature_list;
+ std::vector<StringPiece> disabled_feature_list;
+};
+
+// Features in |feature_vector| came from |merged_features| in
+// OverrideFeatures() and contains linkage with field trial is case when they
+// have parameters (with '<' simbol). In |feature_name| name is already cleared
+// with GetFeatureName() and also could be without parameters.
+bool ContainsFeature(const std::vector<StringPiece>& feature_vector,
+ StringPiece feature_name) {
+ auto iter = std::find_if(feature_vector.begin(), feature_vector.end(),
+ [&feature_name](const StringPiece& a) {
+ return GetFeatureName(a) == feature_name;
+ });
+ return iter != feature_vector.end();
+}
+
+// Merges previously-specified feature overrides with those passed into one of
+// the Init() methods. |features| should be a list of features previously
+// overridden to be in the |override_state|. |merged_features| should contain
+// the enabled and disabled features passed into the Init() method, plus any
+// overrides merged as a result of previous calls to this function.
+void OverrideFeatures(const std::string& features,
+ FeatureList::OverrideState override_state,
+ Features* merged_features) {
+ std::vector<StringPiece> features_list =
+ SplitStringPiece(features, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+
+ for (StringPiece feature : features_list) {
+ StringPiece feature_name = GetFeatureName(feature);
+
+ if (ContainsFeature(merged_features->enabled_feature_list, feature_name) ||
+ ContainsFeature(merged_features->disabled_feature_list, feature_name)) {
+ continue;
+ }
+
+ if (override_state == FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE) {
+ merged_features->enabled_feature_list.push_back(feature);
+ } else {
+ DCHECK_EQ(override_state,
+ FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE);
+ merged_features->disabled_feature_list.push_back(feature);
+ }
+ }
+}
+
+// Hex encode params so that special characters do not break formatting.
+std::string HexEncodeString(const std::string& input) {
+ return HexEncode(input.data(), input.size());
+}
+
+// Inverse of HexEncodeString().
+std::string HexDecodeString(const std::string& input) {
+ if (input.empty())
+ return std::string();
+ std::string bytes;
+ bool result = HexStringToString(input, &bytes);
+ DCHECK(result);
+ return bytes;
+}
+
+} // namespace
+
+ScopedFeatureList::FeatureAndParams::FeatureAndParams(
+ const Feature& feature,
+ const FieldTrialParams& params)
+ : feature(feature), params(params) {}
+
+ScopedFeatureList::FeatureAndParams::~FeatureAndParams() = default;
+
+ScopedFeatureList::FeatureAndParams::FeatureAndParams(
+ const FeatureAndParams& other) = default;
+
+ScopedFeatureList::ScopedFeatureList() = default;
+
+ScopedFeatureList::~ScopedFeatureList() {
+ Reset();
+}
+
+void ScopedFeatureList::Reset() {
+ // If one of the Init() functions was never called, don't reset anything.
+ if (!init_called_)
+ return;
+
+ init_called_ = false;
+
+ FeatureList::ClearInstanceForTesting();
+
+ if (field_trial_list_) {
+ field_trial_list_.reset();
+
+ // Restore params to how they were before.
+ FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
+ AssociateFieldTrialParamsFromString(original_params_, &HexDecodeString);
+
+ FieldTrialList::RestoreInstanceForTesting(original_field_trial_list_);
+ original_field_trial_list_ = nullptr;
+ }
+ if (original_feature_list_)
+ FeatureList::RestoreInstanceForTesting(std::move(original_feature_list_));
+}
+
+void ScopedFeatureList::Init() {
+ InitWithFeaturesImpl({}, {}, {});
+}
+
+void ScopedFeatureList::InitWithFeatureList(
+ std::unique_ptr<FeatureList> feature_list) {
+ DCHECK(!original_feature_list_);
+ original_feature_list_ = FeatureList::ClearInstanceForTesting();
+ FeatureList::SetInstance(std::move(feature_list));
+ init_called_ = true;
+}
+
+void ScopedFeatureList::InitFromCommandLine(
+ const std::string& enable_features,
+ const std::string& disable_features) {
+ std::unique_ptr<FeatureList> feature_list(new FeatureList);
+ feature_list->InitializeFromCommandLine(enable_features, disable_features);
+ InitWithFeatureList(std::move(feature_list));
+}
+
+void ScopedFeatureList::InitWithFeatures(
+ const std::vector<Feature>& enabled_features,
+ const std::vector<Feature>& disabled_features) {
+ InitWithFeaturesImpl(enabled_features, {}, disabled_features);
+}
+
+void ScopedFeatureList::InitAndEnableFeature(const Feature& feature) {
+ InitWithFeaturesImpl({feature}, {}, {});
+}
+
+void ScopedFeatureList::InitAndDisableFeature(const Feature& feature) {
+ InitWithFeaturesImpl({}, {}, {feature});
+}
+
+void ScopedFeatureList::InitWithFeatureState(const Feature& feature,
+ bool enabled) {
+ if (enabled) {
+ InitAndEnableFeature(feature);
+ } else {
+ InitAndDisableFeature(feature);
+ }
+}
+
+void ScopedFeatureList::InitWithFeaturesImpl(
+ const std::vector<Feature>& enabled_features,
+ const std::vector<FeatureAndParams>& enabled_features_and_params,
+ const std::vector<Feature>& disabled_features) {
+ DCHECK(!init_called_);
+ DCHECK(enabled_features.empty() || enabled_features_and_params.empty());
+
+ Features merged_features;
+ if (!enabled_features_and_params.empty()) {
+ merged_features.enabled_feature_list =
+ GetFeatureVectorFromFeaturesAndParams(enabled_features_and_params);
+ } else {
+ merged_features.enabled_feature_list = GetFeatureVector(enabled_features);
+ }
+ merged_features.disabled_feature_list = GetFeatureVector(disabled_features);
+
+ std::string current_enabled_features;
+ std::string current_disabled_features;
+ FeatureList* feature_list = FeatureList::GetInstance();
+ if (feature_list) {
+ feature_list->GetFeatureOverrides(&current_enabled_features,
+ &current_disabled_features);
+ }
+
+ // Save off the existing field trials and params.
+ std::string existing_trial_state;
+ FieldTrialList::AllStatesToString(&existing_trial_state, true);
+ original_params_ = FieldTrialList::AllParamsToString(true, &HexEncodeString);
+
+ // Back up the current field trial list, to be restored in Reset().
+ original_field_trial_list_ = FieldTrialList::BackupInstanceForTesting();
+
+ // Create a field trial list, to which we'll add trials corresponding to the
+ // features that have params, before restoring the field trial state from the
+ // previous instance, further down in this function.
+ field_trial_list_ =
+ std::make_unique<FieldTrialList>(std::make_unique<MockEntropyProvider>());
+
+ // Associate override params. This needs to be done before trial state gets
+ // restored, as that will activate trials, locking down param association.
+ auto* field_trial_param_associator = FieldTrialParamAssociator::GetInstance();
+ std::vector<std::string> features_with_trial;
+ auto feature_it = merged_features.enabled_feature_list.begin();
+ for (const auto& enabled_feature : enabled_features_and_params) {
+ const std::string feature_name = enabled_feature.feature.name;
+ const std::string trial_name =
+ "scoped_feature_list_trial_for_" + feature_name;
+
+ scoped_refptr<FieldTrial> field_trial_override =
+ FieldTrialList::CreateFieldTrial(trial_name, kTrialGroup);
+ DCHECK(field_trial_override);
+
+ field_trial_param_associator->ClearParamsForTesting(trial_name,
+ kTrialGroup);
+ bool success = field_trial_param_associator->AssociateFieldTrialParams(
+ trial_name, kTrialGroup, enabled_feature.params);
+ DCHECK(success);
+
+ features_with_trial.push_back(feature_name + "<" + trial_name);
+ *feature_it = features_with_trial.back();
+ ++feature_it;
+ }
+ // Restore other field trials. Note: We don't need to do anything for params
+ // here because the param associator already has the right state, which has
+ // been backed up via |original_params_| to be restored later.
+ FieldTrialList::CreateTrialsFromString(existing_trial_state, {});
+
+ OverrideFeatures(current_enabled_features,
+ FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
+ &merged_features);
+ OverrideFeatures(current_disabled_features,
+ FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE,
+ &merged_features);
+
+ std::string enabled = JoinString(merged_features.enabled_feature_list, ",");
+ std::string disabled = JoinString(merged_features.disabled_feature_list, ",");
+ InitFromCommandLine(enabled, disabled);
+}
+
+void ScopedFeatureList::InitAndEnableFeatureWithParameters(
+ const Feature& feature,
+ const FieldTrialParams& feature_parameters) {
+ InitWithFeaturesAndParameters({{feature, feature_parameters}}, {});
+}
+
+void ScopedFeatureList::InitWithFeaturesAndParameters(
+ const std::vector<FeatureAndParams>& enabled_features,
+ const std::vector<Feature>& disabled_features) {
+ InitWithFeaturesImpl({}, enabled_features, disabled_features);
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/scoped_feature_list.h b/chromium/base/test/scoped_feature_list.h
new file mode 100644
index 00000000000..1d5bc7e3304
--- /dev/null
+++ b/chromium/base/test/scoped_feature_list.h
@@ -0,0 +1,152 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_FEATURE_LIST_H_
+#define BASE_TEST_SCOPED_FEATURE_LIST_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/feature_list.h"
+#include "base/memory/ref_counted.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
+
+namespace base {
+namespace test {
+
+// ScopedFeatureList resets the global FeatureList instance to a new empty
+// instance and restores the original instance upon destruction. When using the
+// non-deprecated APIs, a corresponding FieldTrialList is also created.
+//
+// Note: Re-using the same object is not allowed. To reset the feature
+// list and initialize it anew, destroy an existing scoped list and init
+// a new one.
+//
+// If multiple instances of this class are used in a nested fashion, they
+// should be destroyed in the opposite order of their Init*() methods being
+// called.
+//
+// ScopedFeatureList needs to be initialized (via one of Init*() methods)
+// before running code that inspects the state of features, such as in the
+// constructor of the test harness.
+//
+// WARNING: To be clear, in multithreaded test environments (such as browser
+// tests) there may background threads using FeatureList before the test body is
+// even entered. In these cases it is imperative that ScopedFeatureList be
+// initialized BEFORE those threads are started, hence the recommendation to do
+// initialization in the test harness's constructor.
+class ScopedFeatureList final {
+ public:
+ ScopedFeatureList();
+ ~ScopedFeatureList();
+
+ struct FeatureAndParams {
+ FeatureAndParams(const Feature& feature, const FieldTrialParams& params);
+ ~FeatureAndParams();
+
+ FeatureAndParams(const FeatureAndParams& other);
+
+ const Feature& feature;
+ const FieldTrialParams params;
+ };
+
+ // Resets the instance to a non-initialized state.
+ void Reset();
+
+ // Initializes and registers a FeatureList instance without any additional
+ // enabled or disabled features. Existing state, if any, will be kept. This is
+ // equivalent to calling InitWithFeatures({}, {}).
+ void Init();
+
+ // WARNING: This method will reset any globally configured features to their
+ // default values, which can hide feature interaction bugs. Please use
+ // sparingly. https://crbug.com/713390
+ // Initializes and registers the given FeatureList instance.
+ void InitWithFeatureList(std::unique_ptr<FeatureList> feature_list);
+
+ // WARNING: This method will reset any globally configured features to their
+ // default values, which can hide feature interaction bugs. Please use
+ // sparingly. https://crbug.com/713390
+ // Initializes and registers a FeatureList instance with only the given
+ // enabled and disabled features (comma-separated names).
+ void InitFromCommandLine(const std::string& enable_features,
+ const std::string& disable_features);
+
+ // Initializes and registers a FeatureList instance based on present
+ // FeatureList and overridden with the given enabled and disabled features.
+ // Any feature overrides already present in the global FeatureList will
+ // continue to apply, unless they conflict with the overrides passed into this
+ // method. This is important for testing potentially unexpected feature
+ // interactions.
+ void InitWithFeatures(const std::vector<Feature>& enabled_features,
+ const std::vector<Feature>& disabled_features);
+
+ // Initializes and registers a FeatureList instance based on present
+ // FeatureList and overridden with single enabled feature.
+ void InitAndEnableFeature(const Feature& feature);
+
+ // Initializes and registers a FeatureList instance based on present
+ // FeatureList and overridden with single enabled feature and associated field
+ // trial parameters.
+ // Note: this creates a scoped global field trial list if there is not
+ // currently one.
+ void InitAndEnableFeatureWithParameters(
+ const Feature& feature,
+ const FieldTrialParams& feature_parameters);
+
+ // Initializes and registers a FeatureList instance based on present
+ // FeatureList and overridden with the given enabled features and the
+ // specified field trial parameters, and the given disabled features.
+ // Note: This creates a scoped global field trial list if there is not
+ // currently one.
+ void InitWithFeaturesAndParameters(
+ const std::vector<FeatureAndParams>& enabled_features,
+ const std::vector<Feature>& disabled_features);
+
+ // Initializes and registers a FeatureList instance based on present
+ // FeatureList and overridden with single disabled feature.
+ void InitAndDisableFeature(const Feature& feature);
+
+ // Initializes and registers a FeatureList instance based on present
+ // FeatureList and overriden with a single feature either enabled or
+ // disabled depending on |enabled|.
+ void InitWithFeatureState(const Feature& feature, bool enabled);
+
+ private:
+ // Initializes and registers a FeatureList instance based on present
+ // FeatureList and overridden with the given enabled and disabled features.
+ // Any feature overrides already present in the global FeatureList will
+ // continue to apply, unless they conflict with the overrides passed into this
+ // method.
+ // Features to enable may be specified through either |enabled_features| or
+ // |enabled_feature_and_params|, but not both (i.e. one of these must be
+ // empty).
+ void InitWithFeaturesImpl(
+ const std::vector<Feature>& enabled_features,
+ const std::vector<FeatureAndParams>& enabled_features_and_params,
+ const std::vector<Feature>& disabled_features);
+
+ // Initializes and registers a FeatureList instance based on present
+ // FeatureList and overridden with single enabled feature and associated field
+ // trial override.
+ // |trial| is expected to outlive the ScopedFeatureList.
+ void InitAndEnableFeatureWithFieldTrialOverride(const Feature& feature,
+ FieldTrial* trial);
+
+ bool init_called_ = false;
+ std::unique_ptr<FeatureList> original_feature_list_;
+ base::FieldTrialList* original_field_trial_list_;
+ std::string original_params_;
+ std::unique_ptr<base::FieldTrialList> field_trial_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedFeatureList);
+};
+
+} // namespace test
+} // namespace base
+
+#endif // BASE_TEST_SCOPED_FEATURE_LIST_H_
diff --git a/chromium/base/test/scoped_feature_list_unittest.cc b/chromium/base/test/scoped_feature_list_unittest.cc
new file mode 100644
index 00000000000..53a7bde390a
--- /dev/null
+++ b/chromium/base/test/scoped_feature_list_unittest.cc
@@ -0,0 +1,430 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_feature_list.h"
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace test {
+
+namespace {
+
+const Feature kTestFeature1{"TestFeature1", FEATURE_DISABLED_BY_DEFAULT};
+const Feature kTestFeature2{"TestFeature2", FEATURE_DISABLED_BY_DEFAULT};
+
+void ExpectFeatures(const std::string& enabled_features,
+ const std::string& disabled_features) {
+ FeatureList* list = FeatureList::GetInstance();
+ std::string actual_enabled_features;
+ std::string actual_disabled_features;
+
+ list->GetFeatureOverrides(&actual_enabled_features,
+ &actual_disabled_features);
+
+ EXPECT_EQ(enabled_features, actual_enabled_features);
+ EXPECT_EQ(disabled_features, actual_disabled_features);
+}
+
+} // namespace
+
+class ScopedFeatureListTest : public testing::Test {
+ public:
+ ScopedFeatureListTest() {
+ // Clear default feature list.
+ std::unique_ptr<FeatureList> feature_list(new FeatureList);
+ feature_list->InitializeFromCommandLine(std::string(), std::string());
+ original_feature_list_ = FeatureList::ClearInstanceForTesting();
+ FeatureList::SetInstance(std::move(feature_list));
+ }
+
+ ~ScopedFeatureListTest() override {
+ // Restore feature list.
+ if (original_feature_list_) {
+ FeatureList::ClearInstanceForTesting();
+ FeatureList::RestoreInstanceForTesting(std::move(original_feature_list_));
+ }
+ }
+
+ private:
+ // Save the present FeatureList and restore it after test finish.
+ std::unique_ptr<FeatureList> original_feature_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedFeatureListTest);
+};
+
+TEST_F(ScopedFeatureListTest, BasicScoped) {
+ ExpectFeatures(std::string(), std::string());
+ EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature1));
+ {
+ test::ScopedFeatureList feature_list1;
+ feature_list1.InitFromCommandLine("TestFeature1", std::string());
+ ExpectFeatures("TestFeature1", std::string());
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+ }
+ ExpectFeatures(std::string(), std::string());
+ EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature1));
+}
+
+TEST_F(ScopedFeatureListTest, EnableWithFeatureParameters) {
+ const char kParam1[] = "param_1";
+ const char kParam2[] = "param_2";
+ const char kValue1[] = "value_1";
+ const char kValue2[] = "value_2";
+ std::map<std::string, std::string> parameters;
+ parameters[kParam1] = kValue1;
+ parameters[kParam2] = kValue2;
+
+ ExpectFeatures(std::string(), std::string());
+ EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
+ FieldTrial::ActiveGroups active_groups;
+ FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+ EXPECT_EQ(0u, active_groups.size());
+
+ {
+ test::ScopedFeatureList feature_list;
+
+ feature_list.InitAndEnableFeatureWithParameters(kTestFeature1, parameters);
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+ EXPECT_EQ(kValue1,
+ GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
+ EXPECT_EQ(kValue2,
+ GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
+ active_groups.clear();
+ FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+ EXPECT_EQ(1u, active_groups.size());
+ }
+
+ ExpectFeatures(std::string(), std::string());
+ EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
+ active_groups.clear();
+ FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+ EXPECT_EQ(0u, active_groups.size());
+}
+
+TEST_F(ScopedFeatureListTest, OverrideWithFeatureParameters) {
+ scoped_refptr<FieldTrial> trial =
+ FieldTrialList::CreateFieldTrial("foo", "bar");
+ const char kParam[] = "param_1";
+ const char kValue[] = "value_1";
+ std::map<std::string, std::string> parameters;
+ parameters[kParam] = kValue;
+
+ test::ScopedFeatureList feature_list1;
+ feature_list1.InitFromCommandLine("TestFeature1<foo,TestFeature2",
+ std::string());
+
+ // Check initial state.
+ ExpectFeatures("TestFeature1<foo,TestFeature2", std::string());
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
+ EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
+ EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+
+ {
+ // Override feature with existing field trial.
+ test::ScopedFeatureList feature_list2;
+
+ feature_list2.InitAndEnableFeatureWithParameters(kTestFeature1, parameters);
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
+ EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+ EXPECT_NE(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
+ EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
+ EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
+ }
+
+ // Check that initial state is restored.
+ ExpectFeatures("TestFeature1<foo,TestFeature2", std::string());
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
+ EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
+ EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+
+ {
+ // Override feature with no existing field trial.
+ test::ScopedFeatureList feature_list2;
+
+ feature_list2.InitAndEnableFeatureWithParameters(kTestFeature2, parameters);
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+ EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+ EXPECT_EQ(trial.get()->trial_name(),
+ FeatureList::GetFieldTrial(kTestFeature1)->trial_name());
+ EXPECT_EQ(trial.get()->group_name(),
+ FeatureList::GetFieldTrial(kTestFeature1)->group_name());
+ EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
+ }
+
+ // Check that initial state is restored.
+ ExpectFeatures("TestFeature1<foo,TestFeature2", std::string());
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
+ EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
+ EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+}
+
+TEST_F(ScopedFeatureListTest, OverrideMultipleFeaturesWithParameters) {
+ scoped_refptr<FieldTrial> trial1 =
+ FieldTrialList::CreateFieldTrial("foo1", "bar1");
+ const char kParam[] = "param_1";
+ const char kValue1[] = "value_1";
+ const char kValue2[] = "value_2";
+ std::map<std::string, std::string> parameters1;
+ parameters1[kParam] = kValue1;
+ std::map<std::string, std::string> parameters2;
+ parameters2[kParam] = kValue2;
+
+ test::ScopedFeatureList feature_list1;
+ feature_list1.InitFromCommandLine("TestFeature1<foo1,TestFeature2",
+ std::string());
+
+ // Check initial state.
+ ExpectFeatures("TestFeature1<foo1,TestFeature2", std::string());
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
+ EXPECT_EQ(trial1.get(), FeatureList::GetFieldTrial(kTestFeature1));
+ EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+
+ {
+ // Override multiple features with parameters.
+ test::ScopedFeatureList feature_list2;
+ feature_list2.InitWithFeaturesAndParameters(
+ {{kTestFeature1, parameters1}, {kTestFeature2, parameters2}}, {});
+
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
+ EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+ EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+ }
+
+ {
+ // Override a feature with a parameter and disable another one.
+ test::ScopedFeatureList feature_list2;
+ feature_list2.InitWithFeaturesAndParameters({{kTestFeature1, parameters2}},
+ {kTestFeature2});
+
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+ EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature2));
+ EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+ }
+
+ // Check that initial state is restored.
+ ExpectFeatures("TestFeature1<foo1,TestFeature2", std::string());
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
+ EXPECT_EQ(trial1.get(), FeatureList::GetFieldTrial(kTestFeature1));
+ EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+}
+
+TEST_F(ScopedFeatureListTest, ParamsWithSpecialCharsPreserved) {
+ // Check that special characters in param names and values are preserved.
+ const char kParam[] = ";_\\<:>/_!?";
+ const char kValue[] = ",;:/'!?";
+ FieldTrialParams params0 = {{kParam, kValue}};
+
+ test::ScopedFeatureList feature_list0;
+ feature_list0.InitWithFeaturesAndParameters({{kTestFeature1, params0}}, {});
+ EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+
+ {
+ const char kValue1[] = "normal";
+ FieldTrialParams params1 = {{kParam, kValue1}};
+ test::ScopedFeatureList feature_list1;
+ feature_list1.InitWithFeaturesAndParameters({{kTestFeature1, params1}}, {});
+
+ EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+ }
+ EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+
+ {
+ const char kValue2[] = "[<(2)>]";
+ FieldTrialParams params2 = {{kParam, kValue2}};
+ test::ScopedFeatureList feature_list2;
+ feature_list2.InitWithFeaturesAndParameters({{kTestFeature2, params2}}, {});
+
+ EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+ EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+ }
+ EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+}
+
+TEST_F(ScopedFeatureListTest, ParamsWithEmptyValue) {
+ const char kParam[] = "p";
+ const char kEmptyValue[] = "";
+ FieldTrialParams params = {{kParam, kEmptyValue}};
+
+ test::ScopedFeatureList feature_list0;
+ feature_list0.InitWithFeaturesAndParameters({{kTestFeature1, params}}, {});
+ EXPECT_EQ(kEmptyValue,
+ GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+ {
+ const char kValue1[] = "normal";
+ FieldTrialParams params1 = {{kParam, kValue1}};
+ test::ScopedFeatureList feature_list1;
+ feature_list1.InitWithFeaturesAndParameters({{kTestFeature1, params1}}, {});
+
+ EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+ }
+ EXPECT_EQ(kEmptyValue,
+ GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+}
+
+TEST_F(ScopedFeatureListTest, EnableFeatureOverrideDisable) {
+ test::ScopedFeatureList feature_list1;
+ feature_list1.InitWithFeatures({}, {kTestFeature1});
+
+ {
+ test::ScopedFeatureList feature_list2;
+ feature_list2.InitWithFeatures({kTestFeature1}, {});
+ ExpectFeatures("TestFeature1", std::string());
+ }
+}
+
+TEST_F(ScopedFeatureListTest, FeatureOverrideNotMakeDuplicate) {
+ test::ScopedFeatureList feature_list1;
+ feature_list1.InitWithFeatures({}, {kTestFeature1});
+
+ {
+ test::ScopedFeatureList feature_list2;
+ feature_list2.InitWithFeatures({}, {kTestFeature1});
+ ExpectFeatures(std::string(), "TestFeature1");
+ }
+}
+
+TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithDefault) {
+ test::ScopedFeatureList feature_list1;
+ feature_list1.InitFromCommandLine("*TestFeature1", std::string());
+
+ {
+ test::ScopedFeatureList feature_list2;
+ feature_list2.InitWithFeatures({kTestFeature1}, {});
+ ExpectFeatures("TestFeature1", std::string());
+ }
+}
+
+TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithDefault2) {
+ test::ScopedFeatureList feature_list1;
+ feature_list1.InitFromCommandLine("*TestFeature1", std::string());
+
+ {
+ test::ScopedFeatureList feature_list2;
+ feature_list2.InitWithFeatures({}, {kTestFeature1});
+ ExpectFeatures(std::string(), "TestFeature1");
+ }
+}
+
+TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithEnabledFieldTrial) {
+ test::ScopedFeatureList feature_list1;
+
+ std::unique_ptr<FeatureList> feature_list(new FeatureList);
+ FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample", "A");
+ feature_list->RegisterFieldTrialOverride(
+ kTestFeature1.name, FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
+ feature_list1.InitWithFeatureList(std::move(feature_list));
+
+ {
+ test::ScopedFeatureList feature_list2;
+ feature_list2.InitWithFeatures({kTestFeature1}, {});
+ ExpectFeatures("TestFeature1", std::string());
+ }
+}
+
+TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithDisabledFieldTrial) {
+ test::ScopedFeatureList feature_list1;
+
+ std::unique_ptr<FeatureList> feature_list(new FeatureList);
+ FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample", "A");
+ feature_list->RegisterFieldTrialOverride(
+ kTestFeature1.name, FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
+ feature_list1.InitWithFeatureList(std::move(feature_list));
+
+ {
+ test::ScopedFeatureList feature_list2;
+ feature_list2.InitWithFeatures({kTestFeature1}, {});
+ ExpectFeatures("TestFeature1", std::string());
+ }
+}
+
+TEST_F(ScopedFeatureListTest, FeatureOverrideKeepsOtherExistingFeature) {
+ test::ScopedFeatureList feature_list1;
+ feature_list1.InitWithFeatures({}, {kTestFeature1});
+
+ {
+ test::ScopedFeatureList feature_list2;
+ feature_list2.InitWithFeatures({}, {kTestFeature2});
+ EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature1));
+ EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature2));
+ }
+}
+
+TEST_F(ScopedFeatureListTest, FeatureOverrideKeepsOtherExistingFeature2) {
+ test::ScopedFeatureList feature_list1;
+ feature_list1.InitWithFeatures({}, {kTestFeature1});
+
+ {
+ test::ScopedFeatureList feature_list2;
+ feature_list2.InitWithFeatures({kTestFeature2}, {});
+ ExpectFeatures("TestFeature2", "TestFeature1");
+ }
+}
+
+TEST_F(ScopedFeatureListTest, FeatureOverrideKeepsOtherExistingDefaultFeature) {
+ test::ScopedFeatureList feature_list1;
+ feature_list1.InitFromCommandLine("*TestFeature1", std::string());
+
+ {
+ test::ScopedFeatureList feature_list2;
+ feature_list2.InitWithFeatures({}, {kTestFeature2});
+ ExpectFeatures("*TestFeature1", "TestFeature2");
+ }
+}
+
+TEST_F(ScopedFeatureListTest, ScopedFeatureListIsNoopWhenNotInitialized) {
+ test::ScopedFeatureList feature_list1;
+ feature_list1.InitFromCommandLine("*TestFeature1", std::string());
+
+ // A ScopedFeatureList on which Init() is not called should not reset things
+ // when going out of scope.
+ { test::ScopedFeatureList feature_list2; }
+
+ ExpectFeatures("*TestFeature1", std::string());
+}
+
+TEST(ScopedFeatureListTestWithMemberList, ScopedFeatureListLocalOverride) {
+ test::ScopedFeatureList initial_feature_list;
+ initial_feature_list.InitAndDisableFeature(kTestFeature1);
+ {
+ base::test::ScopedFeatureList scoped_features;
+ scoped_features.InitAndEnableFeatureWithParameters(kTestFeature1,
+ {{"mode", "nobugs"}});
+ ASSERT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+ }
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/scoped_field_trial_list_resetter.cc b/chromium/base/test/scoped_field_trial_list_resetter.cc
new file mode 100644
index 00000000000..0bc657b8229
--- /dev/null
+++ b/chromium/base/test/scoped_field_trial_list_resetter.cc
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_field_trial_list_resetter.h"
+
+#include "base/metrics/field_trial.h"
+
+namespace base {
+namespace test {
+
+ScopedFieldTrialListResetter::ScopedFieldTrialListResetter()
+ : original_field_trial_list_(
+ base::FieldTrialList::BackupInstanceForTesting()) {}
+
+ScopedFieldTrialListResetter::~ScopedFieldTrialListResetter() {
+ base::FieldTrialList::RestoreInstanceForTesting(original_field_trial_list_);
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/scoped_field_trial_list_resetter.h b/chromium/base/test/scoped_field_trial_list_resetter.h
new file mode 100644
index 00000000000..d7d2dcd35e9
--- /dev/null
+++ b/chromium/base/test/scoped_field_trial_list_resetter.h
@@ -0,0 +1,36 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_FIELD_TRIAL_LIST_RESETTER_H_
+#define BASE_TEST_SCOPED_FIELD_TRIAL_LIST_RESETTER_H_
+
+namespace base {
+
+class FieldTrialList;
+
+namespace test {
+
+// DISCLAIMER: Please use ScopedFeatureList except for advanced cases where
+// custom instantiation of FieldTrialList is required.
+//
+// ScopedFieldTrialListResetter resets the global FieldTrialList instance to
+// null, and restores the original state when the class goes out of scope. This
+// allows client code to initialize FieldTrialList instances in a custom
+// fashion.
+class ScopedFieldTrialListResetter final {
+ public:
+ ScopedFieldTrialListResetter();
+ ScopedFieldTrialListResetter(const ScopedFieldTrialListResetter&) = delete;
+ ScopedFieldTrialListResetter(ScopedFieldTrialListResetter&&) = delete;
+
+ ~ScopedFieldTrialListResetter();
+
+ private:
+ base::FieldTrialList* const original_field_trial_list_;
+};
+
+} // namespace test
+} // namespace base
+
+#endif // BASE_TEST_SCOPED_FIELD_TRIAL_LIST_RESETTER_H_
diff --git a/chromium/base/test/scoped_locale.cc b/chromium/base/test/scoped_locale.cc
new file mode 100644
index 00000000000..c0182842b6d
--- /dev/null
+++ b/chromium/base/test/scoped_locale.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_locale.h"
+
+#include <locale.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+ScopedLocale::ScopedLocale(const std::string& locale) {
+ prev_locale_ = setlocale(LC_ALL, nullptr);
+ EXPECT_TRUE(setlocale(LC_ALL, locale.c_str()) != nullptr)
+ << "Failed to set locale: " << locale;
+}
+
+ScopedLocale::~ScopedLocale() {
+ EXPECT_STREQ(prev_locale_.c_str(), setlocale(LC_ALL, prev_locale_.c_str()));
+}
+
+} // namespace base
diff --git a/chromium/base/test/scoped_locale.h b/chromium/base/test/scoped_locale.h
new file mode 100644
index 00000000000..ef64e98f8eb
--- /dev/null
+++ b/chromium/base/test/scoped_locale.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_LOCALE_H_
+#define BASE_TEST_SCOPED_LOCALE_H_
+
+#include <string>
+
+#include "base/macros.h"
+
+namespace base {
+
+// Sets the given |locale| on construction, and restores the previous locale
+// on destruction.
+class ScopedLocale {
+ public:
+ explicit ScopedLocale(const std::string& locale);
+ ~ScopedLocale();
+
+ private:
+ std::string prev_locale_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedLocale);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_SCOPED_LOCALE_H_
diff --git a/chromium/base/test/scoped_mock_clock_override.cc b/chromium/base/test/scoped_mock_clock_override.cc
new file mode 100644
index 00000000000..46cc88437cd
--- /dev/null
+++ b/chromium/base/test/scoped_mock_clock_override.cc
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_mock_clock_override.h"
+
+namespace base {
+
+ScopedMockClockOverride* ScopedMockClockOverride::scoped_mock_clock_ = nullptr;
+
+ScopedMockClockOverride::ScopedMockClockOverride()
+ : // Start the offset past zero so that it's not treated as a null value.
+ offset_(TimeDelta::FromDays(365)) {
+ DCHECK(!scoped_mock_clock_)
+ << "Nested ScopedMockClockOverrides are not supported.";
+
+ scoped_mock_clock_ = this;
+
+ time_clock_overrides_ = std::make_unique<subtle::ScopedTimeClockOverrides>(
+ &ScopedMockClockOverride::Now, &ScopedMockClockOverride::NowTicks,
+ &ScopedMockClockOverride::NowThreadTicks);
+}
+
+ScopedMockClockOverride::~ScopedMockClockOverride() {
+ scoped_mock_clock_ = nullptr;
+}
+
+Time ScopedMockClockOverride::Now() {
+ return Time() + scoped_mock_clock_->offset_;
+}
+
+TimeTicks ScopedMockClockOverride::NowTicks() {
+ return TimeTicks() + scoped_mock_clock_->offset_;
+}
+
+ThreadTicks ScopedMockClockOverride::NowThreadTicks() {
+ return ThreadTicks() + scoped_mock_clock_->offset_;
+}
+
+void ScopedMockClockOverride::Advance(TimeDelta delta) {
+ DCHECK_GT(delta, base::TimeDelta())
+ << "Monotonically increasing time may not go backwards";
+ offset_ += delta;
+}
+
+} // namespace base
diff --git a/chromium/base/test/scoped_mock_clock_override.h b/chromium/base/test/scoped_mock_clock_override.h
new file mode 100644
index 00000000000..9f7a7e5d5a6
--- /dev/null
+++ b/chromium/base/test/scoped_mock_clock_override.h
@@ -0,0 +1,54 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_MOCK_CLOCK_OVERRIDE_H_
+#define BASE_TEST_SCOPED_MOCK_CLOCK_OVERRIDE_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "base/time/time_override.h"
+
+namespace base {
+
+// Override the return value of Time::Now(), Time::NowFromSystemTime(),
+// TimeTicks::Now(), and ThreadTicks::Now() through a simple advanceable clock.
+//
+// This utility is intended to support tests that:
+//
+// - Depend on large existing codebases that call TimeXYZ::Now() directly or
+// - Have no ability to inject a TickClock into the code getting the time
+// (e.g. integration tests in which a TickClock would be several layers
+// removed from the test code)
+//
+// For new unit tests, developers are highly encouraged to structure new code
+// around a dependency injected base::Clock, base::TickClock, etc. to be able
+// to supply a mock time in tests without a global override.
+//
+// NOTE: ScopedMockClockOverride should be created while single-threaded and
+// before the first call to Now() to avoid threading issues and inconsistencies
+// in returned values. Nested overrides are not allowed.
+class ScopedMockClockOverride {
+ public:
+ ScopedMockClockOverride();
+ ~ScopedMockClockOverride();
+
+ static Time Now();
+ static TimeTicks NowTicks();
+ static ThreadTicks NowThreadTicks();
+
+ void Advance(TimeDelta delta);
+
+ private:
+ std::unique_ptr<base::subtle::ScopedTimeClockOverrides> time_clock_overrides_;
+ TimeDelta offset_;
+ static ScopedMockClockOverride* scoped_mock_clock_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedMockClockOverride);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_SCOPED_MOCK_CLOCK_OVERRIDE_H_
diff --git a/chromium/base/test/scoped_mock_clock_override_unittest.cc b/chromium/base/test/scoped_mock_clock_override_unittest.cc
new file mode 100644
index 00000000000..ab935e07db9
--- /dev/null
+++ b/chromium/base/test/scoped_mock_clock_override_unittest.cc
@@ -0,0 +1,104 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_mock_clock_override.h"
+
+#include "base/build_time.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+#if defined(OS_FUCHSIA)
+// TODO(https://crbug.com/1060357): Enable when RTC flake is fixed.
+#define MAYBE_Time DISABLED_Time
+#else
+#define MAYBE_Time Time
+#endif
+
+TEST(ScopedMockClockOverrideTest, MAYBE_Time) {
+ // Choose a reference time that we know to be in the past but close to now.
+ Time build_time = GetBuildTime();
+
+ // Override is not active. All Now() methods should return a time greater than
+ // the build time.
+ EXPECT_LT(build_time, Time::Now());
+ EXPECT_GT(Time::Max(), Time::Now());
+ EXPECT_LT(build_time, Time::NowFromSystemTime());
+ EXPECT_GT(Time::Max(), Time::NowFromSystemTime());
+
+ {
+ // Set override.
+ ScopedMockClockOverride mock_clock;
+
+ EXPECT_NE(Time(), Time::Now());
+ Time start = Time::Now();
+ mock_clock.Advance(TimeDelta::FromSeconds(1));
+ EXPECT_EQ(start + TimeDelta::FromSeconds(1), Time::Now());
+ }
+
+ // All methods return real time again.
+ EXPECT_LT(build_time, Time::Now());
+ EXPECT_GT(Time::Max(), Time::Now());
+ EXPECT_LT(build_time, Time::NowFromSystemTime());
+ EXPECT_GT(Time::Max(), Time::NowFromSystemTime());
+}
+
+TEST(ScopedMockClockOverrideTest, TimeTicks) {
+ // Override is not active. All Now() methods should return a sensible value.
+ EXPECT_LT(TimeTicks::UnixEpoch(), TimeTicks::Now());
+ EXPECT_GT(TimeTicks::Max(), TimeTicks::Now());
+ EXPECT_LT(TimeTicks::UnixEpoch() + TimeDelta::FromDays(365),
+ TimeTicks::Now());
+
+ {
+ // Set override.
+ ScopedMockClockOverride mock_clock;
+
+ EXPECT_NE(TimeTicks(), TimeTicks::Now());
+ TimeTicks start = TimeTicks::Now();
+ mock_clock.Advance(TimeDelta::FromSeconds(1));
+ EXPECT_EQ(start + TimeDelta::FromSeconds(1), TimeTicks::Now());
+ }
+
+ // All methods return real ticks again.
+ EXPECT_LT(TimeTicks::UnixEpoch(), TimeTicks::Now());
+ EXPECT_GT(TimeTicks::Max(), TimeTicks::Now());
+ EXPECT_LT(TimeTicks::UnixEpoch() + TimeDelta::FromDays(365),
+ TimeTicks::Now());
+}
+
+TEST(ScopedMockClockOverrideTest, ThreadTicks) {
+ if (ThreadTicks::IsSupported()) {
+ ThreadTicks::WaitUntilInitialized();
+
+ // Override is not active. All Now() methods should return a sensible value.
+ ThreadTicks initial_thread_ticks = ThreadTicks::Now();
+ EXPECT_LE(initial_thread_ticks, ThreadTicks::Now());
+ EXPECT_GT(ThreadTicks::Max(), ThreadTicks::Now());
+ EXPECT_LT(ThreadTicks(), ThreadTicks::Now());
+
+ {
+ // Set override.
+ ScopedMockClockOverride mock_clock;
+
+ EXPECT_NE(ThreadTicks(), ThreadTicks::Now());
+ ThreadTicks start = ThreadTicks::Now();
+ mock_clock.Advance(TimeDelta::FromSeconds(1));
+ EXPECT_EQ(start + TimeDelta::FromSeconds(1), ThreadTicks::Now());
+ }
+
+ // All methods return real ticks again.
+ EXPECT_LE(initial_thread_ticks, ThreadTicks::Now());
+ EXPECT_GT(ThreadTicks::Max(), ThreadTicks::Now());
+ EXPECT_LT(ThreadTicks(), ThreadTicks::Now());
+ }
+}
+
+} // namespace
+
+} // namespace base
diff --git a/chromium/base/test/scoped_mock_time_message_loop_task_runner.cc b/chromium/base/test/scoped_mock_time_message_loop_task_runner.cc
new file mode 100644
index 00000000000..0ace2923566
--- /dev/null
+++ b/chromium/base/test/scoped_mock_time_message_loop_task_runner.cc
@@ -0,0 +1,38 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_mock_time_message_loop_task_runner.h"
+
+#include "base/bind.h"
+#include "base/check_op.h"
+#include "base/message_loop/message_loop_current.h"
+#include "base/run_loop.h"
+#include "base/test/test_pending_task.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+
+namespace base {
+
+ScopedMockTimeMessageLoopTaskRunner::ScopedMockTimeMessageLoopTaskRunner()
+ : task_runner_(new TestMockTimeTaskRunner),
+ previous_task_runner_(ThreadTaskRunnerHandle::Get()) {
+ DCHECK(MessageLoopCurrent::Get());
+ // To ensure that we process any initialization tasks posted to the
+ // MessageLoop by a test fixture before replacing its TaskRunner.
+ RunLoop().RunUntilIdle();
+ MessageLoopCurrent::Get()->SetTaskRunner(task_runner_);
+}
+
+ScopedMockTimeMessageLoopTaskRunner::~ScopedMockTimeMessageLoopTaskRunner() {
+ DCHECK(previous_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_EQ(task_runner_, ThreadTaskRunnerHandle::Get());
+ for (auto& pending_task : task_runner_->TakePendingTasks()) {
+ previous_task_runner_->PostDelayedTask(
+ pending_task.location, std::move(pending_task.task),
+ pending_task.GetTimeToRun() - task_runner_->NowTicks());
+ }
+ MessageLoopCurrent::Get()->SetTaskRunner(std::move(previous_task_runner_));
+}
+
+} // namespace base
diff --git a/chromium/base/test/scoped_mock_time_message_loop_task_runner.h b/chromium/base/test/scoped_mock_time_message_loop_task_runner.h
new file mode 100644
index 00000000000..b671304b295
--- /dev/null
+++ b/chromium/base/test/scoped_mock_time_message_loop_task_runner.h
@@ -0,0 +1,45 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_MOCK_TIME_MESSAGE_LOOP_TASK_RUNNER_H_
+#define BASE_TEST_SCOPED_MOCK_TIME_MESSAGE_LOOP_TASK_RUNNER_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/test/test_mock_time_task_runner.h"
+
+namespace base {
+
+class SingleThreadTaskRunner;
+
+// A scoped wrapper around TestMockTimeTaskRunner that replaces
+// MessageLoopCurrent::Get()'s task runner (and consequently
+// ThreadTaskRunnerHandle) with a TestMockTimeTaskRunner and resets it back at
+// the end of its scope.
+//
+// Note: RunLoop() will not work in the scope of a
+// ScopedMockTimeMessageLoopTaskRunner, the underlying TestMockTimeTaskRunner's
+// methods must be used instead to pump tasks.
+//
+// Note: Use TaskEnvironment + TimeSource::MOCK_TIME instead of this in unit
+// tests. In browser tests you unfortunately still need this at the moment to
+// mock delayed tasks on the main thread...
+class ScopedMockTimeMessageLoopTaskRunner {
+ public:
+ ScopedMockTimeMessageLoopTaskRunner();
+ ~ScopedMockTimeMessageLoopTaskRunner();
+
+ TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); }
+ TestMockTimeTaskRunner* operator->() { return task_runner_.get(); }
+
+ private:
+ const scoped_refptr<TestMockTimeTaskRunner> task_runner_;
+ scoped_refptr<SingleThreadTaskRunner> previous_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedMockTimeMessageLoopTaskRunner);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_SCOPED_MOCK_TIME_MESSAGE_LOOP_TASK_RUNNER_H_
diff --git a/chromium/base/test/scoped_mock_time_message_loop_task_runner_unittest.cc b/chromium/base/test/scoped_mock_time_message_loop_task_runner_unittest.cc
new file mode 100644
index 00000000000..f2f34b802d6
--- /dev/null
+++ b/chromium/base/test/scoped_mock_time_message_loop_task_runner_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_mock_time_message_loop_task_runner.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_forward.h"
+#include "base/containers/circular_deque.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop_current.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/test/test_pending_task.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TaskRunner* GetCurrentTaskRunner() {
+ return ThreadTaskRunnerHandle::Get().get();
+}
+
+void AssignTrue(bool* out) {
+ *out = true;
+}
+
+// Pops a task from the front of |pending_tasks| and returns it.
+TestPendingTask PopFront(base::circular_deque<TestPendingTask>* pending_tasks) {
+ TestPendingTask task = std::move(pending_tasks->front());
+ pending_tasks->pop_front();
+ return task;
+}
+
+class ScopedMockTimeMessageLoopTaskRunnerTest : public testing::Test {
+ public:
+ ScopedMockTimeMessageLoopTaskRunnerTest()
+ : original_task_runner_(new TestMockTimeTaskRunner()) {
+ MessageLoopCurrent::Get()->SetTaskRunner(original_task_runner_);
+ }
+
+ protected:
+ TestMockTimeTaskRunner* original_task_runner() {
+ return original_task_runner_.get();
+ }
+
+ private:
+ scoped_refptr<TestMockTimeTaskRunner> original_task_runner_;
+
+ test::SingleThreadTaskEnvironment task_environment_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedMockTimeMessageLoopTaskRunnerTest);
+};
+
+// Verifies a new TaskRunner is installed while a
+// ScopedMockTimeMessageLoopTaskRunner exists and the previous one is installed
+// after destruction.
+TEST_F(ScopedMockTimeMessageLoopTaskRunnerTest, CurrentTaskRunners) {
+ auto scoped_task_runner_ =
+ std::make_unique<ScopedMockTimeMessageLoopTaskRunner>();
+ EXPECT_EQ(scoped_task_runner_->task_runner(), GetCurrentTaskRunner());
+ scoped_task_runner_.reset();
+ EXPECT_EQ(original_task_runner(), GetCurrentTaskRunner());
+}
+
+TEST_F(ScopedMockTimeMessageLoopTaskRunnerTest,
+ IncompleteTasksAreCopiedToPreviousTaskRunnerAfterDestruction) {
+ auto scoped_task_runner_ =
+ std::make_unique<ScopedMockTimeMessageLoopTaskRunner>();
+
+ bool task_10_has_run = false;
+ bool task_11_has_run = false;
+
+ OnceClosure task_1 = DoNothing();
+ OnceClosure task_2 = DoNothing();
+ OnceClosure task_10 = BindOnce(&AssignTrue, &task_10_has_run);
+ OnceClosure task_11 = BindOnce(&AssignTrue, &task_11_has_run);
+
+ constexpr TimeDelta task_1_delay = TimeDelta::FromSeconds(1);
+ constexpr TimeDelta task_2_delay = TimeDelta::FromSeconds(2);
+ constexpr TimeDelta task_10_delay = TimeDelta::FromSeconds(10);
+ constexpr TimeDelta task_11_delay = TimeDelta::FromSeconds(11);
+
+ constexpr TimeDelta step_time_by = TimeDelta::FromSeconds(5);
+
+ GetCurrentTaskRunner()->PostDelayedTask(FROM_HERE, std::move(task_1),
+ task_1_delay);
+ GetCurrentTaskRunner()->PostDelayedTask(FROM_HERE, std::move(task_2),
+ task_2_delay);
+ GetCurrentTaskRunner()->PostDelayedTask(FROM_HERE, std::move(task_10),
+ task_10_delay);
+ GetCurrentTaskRunner()->PostDelayedTask(FROM_HERE, std::move(task_11),
+ task_11_delay);
+
+ scoped_task_runner_->task_runner()->FastForwardBy(step_time_by);
+
+ scoped_task_runner_.reset();
+
+ base::circular_deque<TestPendingTask> pending_tasks =
+ original_task_runner()->TakePendingTasks();
+
+ EXPECT_EQ(2U, pending_tasks.size());
+
+ TestPendingTask pending_task = PopFront(&pending_tasks);
+ EXPECT_FALSE(task_10_has_run);
+ std::move(pending_task.task).Run();
+ EXPECT_TRUE(task_10_has_run);
+ EXPECT_EQ(task_10_delay - step_time_by, pending_task.delay);
+
+ pending_task = PopFront(&pending_tasks);
+ EXPECT_FALSE(task_11_has_run);
+ std::move(pending_task.task).Run();
+ EXPECT_TRUE(task_11_has_run);
+ EXPECT_EQ(task_11_delay - step_time_by, pending_task.delay);
+}
+
+} // namespace
+} // namespace base
diff --git a/chromium/base/test/scoped_os_info_override_win.cc b/chromium/base/test/scoped_os_info_override_win.cc
new file mode 100644
index 00000000000..7415c13234c
--- /dev/null
+++ b/chromium/base/test/scoped_os_info_override_win.cc
@@ -0,0 +1,126 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_os_info_override_win.h"
+
+#include <windows.h>
+
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace test {
+
+ScopedOSInfoOverride::ScopedOSInfoOverride(Type type)
+ : original_info_(base::win::OSInfo::GetInstance()),
+ overriding_info_(CreateInfoOfType(type)) {
+ *base::win::OSInfo::GetInstanceStorage() = overriding_info_.get();
+}
+
+ScopedOSInfoOverride::~ScopedOSInfoOverride() {
+ *base::win::OSInfo::GetInstanceStorage() = original_info_;
+}
+
+// static
+ScopedOSInfoOverride::UniqueOsInfo ScopedOSInfoOverride::CreateInfoOfType(
+ Type type) {
+ _OSVERSIONINFOEXW version_info = {sizeof(version_info)};
+ _SYSTEM_INFO system_info = {};
+ int os_type = 0;
+
+ switch (type) {
+ case Type::kWin10Pro:
+ case Type::kWin10Home:
+ version_info.dwMajorVersion = 10;
+ version_info.dwMinorVersion = 0;
+ version_info.dwBuildNumber = 15063;
+ version_info.wServicePackMajor = 0;
+ version_info.wServicePackMinor = 0;
+ version_info.szCSDVersion[0] = 0;
+ version_info.wProductType = VER_NT_WORKSTATION;
+ version_info.wSuiteMask = VER_SUITE_PERSONAL;
+
+ system_info.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
+ system_info.dwNumberOfProcessors = 1;
+ system_info.dwAllocationGranularity = 8;
+
+ os_type =
+ type == Type::kWin10Home ? PRODUCT_HOME_BASIC : PRODUCT_PROFESSIONAL;
+ break;
+ case Type::kWinServer2016:
+ version_info.dwMajorVersion = 10;
+ version_info.dwMinorVersion = 0;
+ version_info.dwBuildNumber = 17134;
+ version_info.wServicePackMajor = 0;
+ version_info.wServicePackMinor = 0;
+ version_info.szCSDVersion[0] = 0;
+ version_info.wProductType = VER_NT_SERVER;
+ version_info.wSuiteMask = VER_SUITE_ENTERPRISE;
+
+ system_info.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
+ system_info.dwNumberOfProcessors = 4;
+ system_info.dwAllocationGranularity = 64 * 1024;
+
+ os_type = PRODUCT_STANDARD_SERVER;
+ break;
+ case Type::kWin81Pro:
+ version_info.dwMajorVersion = 6;
+ version_info.dwMinorVersion = 3;
+ version_info.dwBuildNumber = 9600;
+ version_info.wServicePackMajor = 0;
+ version_info.wServicePackMinor = 0;
+ version_info.szCSDVersion[0] = 0;
+ version_info.wProductType = VER_NT_WORKSTATION;
+ version_info.wSuiteMask = VER_SUITE_PERSONAL;
+
+ system_info.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
+ system_info.dwNumberOfProcessors = 1;
+ system_info.dwAllocationGranularity = 64 * 1024;
+
+ os_type = PRODUCT_PROFESSIONAL;
+ break;
+ case Type::kWinServer2012R2:
+ version_info.dwMajorVersion = 6;
+ version_info.dwMinorVersion = 3;
+ version_info.dwBuildNumber = 9600;
+ version_info.wServicePackMajor = 0;
+ version_info.wServicePackMinor = 0;
+ version_info.szCSDVersion[0] = 0;
+ version_info.wProductType = VER_NT_SERVER;
+ version_info.wSuiteMask = VER_SUITE_ENTERPRISE;
+
+ system_info.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
+ system_info.dwNumberOfProcessors = 2;
+ system_info.dwAllocationGranularity = 64 * 1024;
+
+ os_type = PRODUCT_STANDARD_SERVER;
+ break;
+ case Type::kWin7ProSP1:
+ version_info.dwMajorVersion = 6;
+ version_info.dwMinorVersion = 1;
+ version_info.dwBuildNumber = 7601;
+ version_info.wServicePackMajor = 1;
+ version_info.wServicePackMinor = 0;
+ wcscpy_s(version_info.szCSDVersion, L"Service Pack 1");
+ version_info.wProductType = VER_NT_WORKSTATION;
+ version_info.wSuiteMask = VER_SUITE_PERSONAL;
+
+ system_info.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
+ system_info.dwNumberOfProcessors = 1;
+ system_info.dwAllocationGranularity = 64 * 1024;
+
+ os_type = PRODUCT_PROFESSIONAL;
+ break;
+ }
+
+ return UniqueOsInfo(new base::win::OSInfo(version_info, system_info, os_type),
+ &ScopedOSInfoOverride::deleter);
+}
+
+// static
+void ScopedOSInfoOverride::deleter(base::win::OSInfo* info) {
+ delete info;
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/scoped_os_info_override_win.h b/chromium/base/test/scoped_os_info_override_win.h
new file mode 100644
index 00000000000..07ae7a964f1
--- /dev/null
+++ b/chromium/base/test/scoped_os_info_override_win.h
@@ -0,0 +1,64 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_OS_INFO_OVERRIDE_WIN_H_
+#define BASE_TEST_SCOPED_OS_INFO_OVERRIDE_WIN_H_
+
+#include <memory>
+
+#include "base/macros.h"
+
+namespace base {
+namespace win {
+class OSInfo;
+} // namespace win
+} // namespace base
+
+namespace base {
+namespace test {
+
+// Helper class to override info returned by base::win::OSInfo::GetIntance()
+// for the lifetime of this object. Upon destruction, the original info at time
+// of object creation is restored.
+class ScopedOSInfoOverride {
+ public:
+ // Types of windows machines that can be used for overriding. Add new
+ // machine types as needed.
+ enum class Type {
+ kWin10Pro,
+ kWin10Home,
+ kWinServer2016,
+ kWin81Pro,
+ kWinServer2012R2,
+ kWin7ProSP1,
+ };
+
+ explicit ScopedOSInfoOverride(Type type);
+ ~ScopedOSInfoOverride();
+
+ private:
+ using UniqueOsInfo =
+ std::unique_ptr<base::win::OSInfo, void (*)(base::win::OSInfo*)>;
+
+ static UniqueOsInfo CreateInfoOfType(Type type);
+
+ // The OSInfo taken by this instance at construction and restored at
+ // destruction.
+ base::win::OSInfo* original_info_;
+
+ // The OSInfo owned by this scoped object and which overrides
+ // base::win::OSInfo::GetIntance() for the lifespan of the object.
+ UniqueOsInfo overriding_info_;
+
+ // Because the dtor of OSInfo is private, a custom deleter is needed to use
+ // unique_ptr.
+ static void deleter(base::win::OSInfo* info);
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedOSInfoOverride);
+};
+
+} // namespace test
+} // namespace base
+
+#endif // BASE_TEST_SCOPED_OS_INFO_OVERRIDE_WIN_H_
diff --git a/chromium/base/test/scoped_path_override.cc b/chromium/base/test/scoped_path_override.cc
new file mode 100644
index 00000000000..dc4a34089ce
--- /dev/null
+++ b/chromium/base/test/scoped_path_override.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_path_override.h"
+
+#include "base/check.h"
+#include "base/path_service.h"
+
+namespace base {
+
+ScopedPathOverride::ScopedPathOverride(int key) : key_(key) {
+ bool result = temp_dir_.CreateUniqueTempDir();
+ CHECK(result);
+ result = PathService::Override(key, temp_dir_.GetPath());
+ CHECK(result);
+}
+
+ScopedPathOverride::ScopedPathOverride(int key, const base::FilePath& dir)
+ : key_(key) {
+ bool result = PathService::Override(key, dir);
+ CHECK(result);
+}
+
+ScopedPathOverride::ScopedPathOverride(int key,
+ const FilePath& path,
+ bool is_absolute,
+ bool create)
+ : key_(key) {
+ bool result =
+ PathService::OverrideAndCreateIfNeeded(key, path, is_absolute, create);
+ CHECK(result);
+}
+
+ScopedPathOverride::~ScopedPathOverride() {
+ bool result = PathService::RemoveOverride(key_);
+ CHECK(result) << "The override seems to have been removed already!";
+}
+
+} // namespace base
diff --git a/chromium/base/test/scoped_path_override.h b/chromium/base/test/scoped_path_override.h
new file mode 100644
index 00000000000..f5891490b1c
--- /dev/null
+++ b/chromium/base/test/scoped_path_override.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_PATH_OVERRIDE_H_
+#define BASE_TEST_SCOPED_PATH_OVERRIDE_H_
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+
+namespace base {
+
+class FilePath;
+
+// Sets a path override on construction, and removes it when the object goes out
+// of scope. This class is intended to be used by tests that need to override
+// paths to ensure their overrides are properly handled and reverted when the
+// scope of the test is left.
+class ScopedPathOverride {
+ public:
+ // Contructor that initializes the override to a scoped temp directory.
+ explicit ScopedPathOverride(int key);
+
+ // Constructor that would use a path provided by the user.
+ ScopedPathOverride(int key, const FilePath& dir);
+
+ // See PathService::OverrideAndCreateIfNeeded.
+ ScopedPathOverride(int key,
+ const FilePath& path,
+ bool is_absolute,
+ bool create);
+ ~ScopedPathOverride();
+
+ private:
+ int key_;
+ ScopedTempDir temp_dir_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedPathOverride);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_SCOPED_PATH_OVERRIDE_H_
diff --git a/chromium/base/test/scoped_run_loop_timeout.cc b/chromium/base/test/scoped_run_loop_timeout.cc
new file mode 100644
index 00000000000..5158c5c4c84
--- /dev/null
+++ b/chromium/base/test/scoped_run_loop_timeout.cc
@@ -0,0 +1,94 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_run_loop_timeout.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/strings/strcat.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace test {
+
+namespace {
+
+bool g_add_gtest_failure_on_timeout = false;
+
+std::string TimeoutMessage(const RepeatingCallback<std::string()>& get_log) {
+ std::string message = "RunLoop::Run() timed out.";
+ if (get_log)
+ StrAppend(&message, {"\n", get_log.Run()});
+ return message;
+}
+
+} // namespace
+
+ScopedRunLoopTimeout::ScopedRunLoopTimeout(const Location& from_here,
+ TimeDelta timeout)
+ : ScopedRunLoopTimeout(from_here, timeout, NullCallback()) {}
+
+ScopedRunLoopTimeout::~ScopedRunLoopTimeout() {
+ RunLoop::SetTimeoutForCurrentThread(nested_timeout_);
+}
+
+ScopedRunLoopTimeout::ScopedRunLoopTimeout(
+ const Location& from_here,
+ TimeDelta timeout,
+ RepeatingCallback<std::string()> on_timeout_log)
+ : nested_timeout_(RunLoop::GetTimeoutForCurrentThread()) {
+ DCHECK_GT(timeout, TimeDelta());
+ run_timeout_.timeout = timeout;
+
+ if (g_add_gtest_failure_on_timeout) {
+ run_timeout_.on_timeout = BindRepeating(
+ [](const Location& from_here,
+ RepeatingCallback<std::string()> on_timeout_log) {
+ GTEST_FAIL_AT(from_here.file_name(), from_here.line_number())
+ << TimeoutMessage(on_timeout_log);
+ },
+ from_here, std::move(on_timeout_log));
+ } else {
+ run_timeout_.on_timeout = BindRepeating(
+ [](const Location& from_here,
+ RepeatingCallback<std::string()> on_timeout_log) {
+ std::string message = TimeoutMessage(on_timeout_log);
+ logging::LogMessage(from_here.file_name(), from_here.line_number(),
+ message.data());
+ },
+ from_here, std::move(on_timeout_log));
+ }
+
+ RunLoop::SetTimeoutForCurrentThread(&run_timeout_);
+}
+
+// static
+bool ScopedRunLoopTimeout::ExistsForCurrentThread() {
+ return RunLoop::GetTimeoutForCurrentThread() != nullptr;
+}
+
+// static
+void ScopedRunLoopTimeout::SetAddGTestFailureOnTimeout() {
+ g_add_gtest_failure_on_timeout = true;
+}
+
+// static
+const RunLoop::RunLoopTimeout*
+ScopedRunLoopTimeout::GetTimeoutForCurrentThread() {
+ return RunLoop::GetTimeoutForCurrentThread();
+}
+
+ScopedDisableRunLoopTimeout::ScopedDisableRunLoopTimeout()
+ : nested_timeout_(RunLoop::GetTimeoutForCurrentThread()) {
+ RunLoop::SetTimeoutForCurrentThread(nullptr);
+}
+
+ScopedDisableRunLoopTimeout::~ScopedDisableRunLoopTimeout() {
+ RunLoop::SetTimeoutForCurrentThread(nested_timeout_);
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/scoped_run_loop_timeout.h b/chromium/base/test/scoped_run_loop_timeout.h
new file mode 100644
index 00000000000..12abd9f4e55
--- /dev/null
+++ b/chromium/base/test/scoped_run_loop_timeout.h
@@ -0,0 +1,107 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_RUN_LOOP_TIMEOUT_H_
+#define BASE_TEST_SCOPED_RUN_LOOP_TIMEOUT_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/run_loop.h"
+#include "base/time/time.h"
+
+namespace content {
+FORWARD_DECLARE_TEST(ContentBrowserTest, RunTimeoutInstalled);
+}
+
+namespace base {
+namespace test {
+
+FORWARD_DECLARE_TEST(TaskEnvironmentTest, SetsDefaultRunTimeout);
+
+// Configures all RunLoop::Run() calls on the current thread to run the
+// supplied |on_timeout| callback if they run for longer than |timeout|.
+//
+// Specifying Run() timeouts per-thread avoids the need to cope with Run()s
+// executing concurrently with ScopedRunLoopTimeout initialization or
+// teardown, and allows "default" timeouts to be specified by suites, rather
+// than explicitly configuring them for every RunLoop, in each test.
+//
+// This is used by test classes including TaskEnvironment and TestSuite to
+// set a default Run() timeout on the main thread of all tests which use them.
+//
+// Tests which have steps which need to Run() for longer than their suite's
+// default (if any) allows can override the active timeout by creating a nested
+// ScopedRunLoopTimeout on their stack, e.g:
+//
+// ScopedRunLoopTimeout default_timeout(kDefaultRunTimeout);
+// ... do other test stuff ...
+// RunLoop().Run(); // Run for up to kDefaultRunTimeout.
+// ...
+// {
+// ScopedRunLoopTimeout specific_timeout(kTestSpecificTimeout);
+// RunLoop().Run(); // Run for up to kTestSpecificTimeout.
+// }
+// ...
+// RunLoop().Run(); // Run for up to kDefaultRunTimeout.
+//
+// The currently-active timeout can also be temporarily disabled:
+// ScopedDisableRunLoopTimeout disable_timeout;
+//
+// By default LOG(FATAL) will be invoked on Run() timeout. Test binaries
+// can opt-in to using ADD_FAILURE() instead by calling
+// SetAddGTestFailureOnTimeout() during process initialization.
+//
+// TaskEnvironment applies a default Run() timeout.
+
+class ScopedRunLoopTimeout {
+ public:
+ ScopedRunLoopTimeout(const Location& from_here, TimeDelta timeout);
+ ~ScopedRunLoopTimeout();
+
+ // Invokes |on_timeout_log| if |timeout| expires, and appends it to the
+ // logged error message.
+ ScopedRunLoopTimeout(const Location& from_here,
+ TimeDelta timeout,
+ RepeatingCallback<std::string()> on_timeout_log);
+
+ ScopedRunLoopTimeout(const ScopedRunLoopTimeout&) = delete;
+ ScopedRunLoopTimeout& operator=(const ScopedRunLoopTimeout&) = delete;
+
+ // Returns true if there is a Run() timeout configured on the current thread.
+ static bool ExistsForCurrentThread();
+
+ static void SetAddGTestFailureOnTimeout();
+
+ protected:
+ FRIEND_TEST_ALL_PREFIXES(ScopedRunLoopRunTimeoutTest, TimesOut);
+ FRIEND_TEST_ALL_PREFIXES(ScopedRunLoopRunTimeoutTest, RunTasksUntilTimeout);
+ FRIEND_TEST_ALL_PREFIXES(TaskEnvironmentTest, SetsDefaultRunTimeout);
+ FRIEND_TEST_ALL_PREFIXES(content::ContentBrowserTest, RunTimeoutInstalled);
+
+ // Exposes the RunLoopTimeout to the friend tests (see above).
+ static const RunLoop::RunLoopTimeout* GetTimeoutForCurrentThread();
+
+ const RunLoop::RunLoopTimeout* const nested_timeout_;
+ RunLoop::RunLoopTimeout run_timeout_;
+};
+
+class ScopedDisableRunLoopTimeout {
+ public:
+ ScopedDisableRunLoopTimeout();
+ ~ScopedDisableRunLoopTimeout();
+
+ ScopedDisableRunLoopTimeout(const ScopedDisableRunLoopTimeout&) = delete;
+ ScopedDisableRunLoopTimeout& operator=(const ScopedDisableRunLoopTimeout&) =
+ delete;
+
+ private:
+ const RunLoop::RunLoopTimeout* const nested_timeout_;
+};
+
+} // namespace test
+} // namespace base
+
+#endif // BASE_TEST_SCOPED_RUN_LOOP_TIMEOUT_H_
diff --git a/chromium/base/test/scoped_run_loop_timeout_unittest.cc b/chromium/base/test/scoped_run_loop_timeout_unittest.cc
new file mode 100644
index 00000000000..c60bf71569e
--- /dev/null
+++ b/chromium/base/test/scoped_run_loop_timeout_unittest.cc
@@ -0,0 +1,79 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_run_loop_timeout.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/gtest_util.h"
+#include "base/test/task_environment.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest-spi.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace test {
+
+TEST(ScopedRunLoopTimeoutTest, TimesOut) {
+ TaskEnvironment task_environment;
+ RunLoop run_loop;
+
+ static constexpr auto kArbitraryTimeout = TimeDelta::FromMilliseconds(10);
+ ScopedRunLoopTimeout run_timeout(FROM_HERE, kArbitraryTimeout);
+
+ // Since the delayed task will be posted only after the message pump starts
+ // running, the ScopedRunLoopTimeout will already have started to elapse,
+ // so if Run() exits at the correct time then our delayed task will not run.
+ SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ BindOnce(IgnoreResult(&SequencedTaskRunner::PostDelayedTask),
+ SequencedTaskRunnerHandle::Get(), FROM_HERE,
+ MakeExpectedNotRunClosure(FROM_HERE), kArbitraryTimeout));
+
+ // This task should get to run before Run() times-out.
+ SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, MakeExpectedRunClosure(FROM_HERE), kArbitraryTimeout);
+
+ // EXPECT_FATAL_FAILURE() can only reference globals and statics.
+ static RunLoop& static_loop = run_loop;
+ EXPECT_FATAL_FAILURE(static_loop.Run(), "Run() timed out.");
+}
+
+TEST(ScopedRunLoopTimeoutTest, RunTasksUntilTimeout) {
+ TaskEnvironment task_environment;
+ RunLoop run_loop;
+
+ static constexpr auto kArbitraryTimeout = TimeDelta::FromMilliseconds(10);
+ ScopedRunLoopTimeout run_timeout(FROM_HERE, kArbitraryTimeout);
+
+ // Posting a task with the same delay as our timeout, immediately before
+ // calling Run(), means it should get to run. Since this uses QuitWhenIdle(),
+ // the Run() timeout callback should also get to run.
+ SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, MakeExpectedRunClosure(FROM_HERE), kArbitraryTimeout);
+
+ // EXPECT_FATAL_FAILURE() can only reference globals and statics.
+ static RunLoop& static_loop = run_loop;
+ EXPECT_FATAL_FAILURE(static_loop.Run(), "Run() timed out.");
+}
+
+TEST(ScopedRunLoopTimeoutTest, OnTimeoutLog) {
+ TaskEnvironment task_environment;
+ RunLoop run_loop;
+
+ static constexpr auto kArbitraryTimeout = TimeDelta::FromMilliseconds(10);
+ ScopedRunLoopTimeout run_timeout(
+ FROM_HERE, kArbitraryTimeout,
+ BindRepeating([]() -> std::string { return "I like kittens!"; }));
+
+ // EXPECT_FATAL_FAILURE() can only reference globals and statics.
+ static RunLoop& static_loop = run_loop;
+ EXPECT_FATAL_FAILURE(static_loop.Run(), "Run() timed out.\nI like kittens!");
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/sequenced_task_runner_test_template.cc b/chromium/base/test/sequenced_task_runner_test_template.cc
new file mode 100644
index 00000000000..bccc301ab7d
--- /dev/null
+++ b/chromium/base/test/sequenced_task_runner_test_template.cc
@@ -0,0 +1,270 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/sequenced_task_runner_test_template.h"
+
+#include <ostream>
+
+#include "base/location.h"
+
+namespace base {
+
+namespace internal {
+
+TaskEvent::TaskEvent(int i, Type type)
+ : i(i), type(type) {
+}
+
+SequencedTaskTracker::SequencedTaskTracker()
+ : next_post_i_(0),
+ task_end_count_(0),
+ task_end_cv_(&lock_) {
+}
+
+void SequencedTaskTracker::PostWrappedNonNestableTask(
+ SequencedTaskRunner* task_runner,
+ OnceClosure task) {
+ AutoLock event_lock(lock_);
+ const int post_i = next_post_i_++;
+ auto wrapped_task =
+ BindOnce(&SequencedTaskTracker::RunTask, this, std::move(task), post_i);
+ task_runner->PostNonNestableTask(FROM_HERE, std::move(wrapped_task));
+ TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostWrappedNestableTask(
+ SequencedTaskRunner* task_runner,
+ OnceClosure task) {
+ AutoLock event_lock(lock_);
+ const int post_i = next_post_i_++;
+ auto wrapped_task =
+ BindOnce(&SequencedTaskTracker::RunTask, this, std::move(task), post_i);
+ task_runner->PostTask(FROM_HERE, std::move(wrapped_task));
+ TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostWrappedDelayedNonNestableTask(
+ SequencedTaskRunner* task_runner,
+ OnceClosure task,
+ TimeDelta delay) {
+ AutoLock event_lock(lock_);
+ const int post_i = next_post_i_++;
+ auto wrapped_task =
+ BindOnce(&SequencedTaskTracker::RunTask, this, std::move(task), post_i);
+ task_runner->PostNonNestableDelayedTask(FROM_HERE, std::move(wrapped_task),
+ delay);
+ TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostNonNestableTasks(
+ SequencedTaskRunner* task_runner,
+ int task_count) {
+ for (int i = 0; i < task_count; ++i) {
+ PostWrappedNonNestableTask(task_runner, OnceClosure());
+ }
+}
+
+void SequencedTaskTracker::RunTask(OnceClosure task, int task_i) {
+ TaskStarted(task_i);
+ if (!task.is_null())
+ std::move(task).Run();
+ TaskEnded(task_i);
+}
+
+void SequencedTaskTracker::TaskPosted(int i) {
+ // Caller must own |lock_|.
+ events_.push_back(TaskEvent(i, TaskEvent::POST));
+}
+
+void SequencedTaskTracker::TaskStarted(int i) {
+ AutoLock lock(lock_);
+ events_.push_back(TaskEvent(i, TaskEvent::START));
+}
+
+void SequencedTaskTracker::TaskEnded(int i) {
+ AutoLock lock(lock_);
+ events_.push_back(TaskEvent(i, TaskEvent::END));
+ ++task_end_count_;
+ task_end_cv_.Signal();
+}
+
+const std::vector<TaskEvent>&
+SequencedTaskTracker::GetTaskEvents() const {
+ return events_;
+}
+
+void SequencedTaskTracker::WaitForCompletedTasks(int count) {
+ AutoLock lock(lock_);
+ while (task_end_count_ < count)
+ task_end_cv_.Wait();
+}
+
+SequencedTaskTracker::~SequencedTaskTracker() = default;
+
+void PrintTo(const TaskEvent& event, std::ostream* os) {
+ *os << "(i=" << event.i << ", type=";
+ switch (event.type) {
+ case TaskEvent::POST: *os << "POST"; break;
+ case TaskEvent::START: *os << "START"; break;
+ case TaskEvent::END: *os << "END"; break;
+ }
+ *os << ")";
+}
+
+namespace {
+
+// Returns the task ordinals for the task event type |type| in the order that
+// they were recorded.
+std::vector<int> GetEventTypeOrder(const std::vector<TaskEvent>& events,
+ TaskEvent::Type type) {
+ std::vector<int> tasks;
+ std::vector<TaskEvent>::const_iterator event;
+ for (event = events.begin(); event != events.end(); ++event) {
+ if (event->type == type)
+ tasks.push_back(event->i);
+ }
+ return tasks;
+}
+
+// Returns all task events for task |task_i|.
+std::vector<TaskEvent::Type> GetEventsForTask(
+ const std::vector<TaskEvent>& events,
+ int task_i) {
+ std::vector<TaskEvent::Type> task_event_orders;
+ std::vector<TaskEvent>::const_iterator event;
+ for (event = events.begin(); event != events.end(); ++event) {
+ if (event->i == task_i)
+ task_event_orders.push_back(event->type);
+ }
+ return task_event_orders;
+}
+
+// Checks that the task events for each task in |events| occur in the order
+// {POST, START, END}, and that there is only one instance of each event type
+// per task.
+::testing::AssertionResult CheckEventOrdersForEachTask(
+ const std::vector<TaskEvent>& events,
+ int task_count) {
+ std::vector<TaskEvent::Type> expected_order;
+ expected_order.push_back(TaskEvent::POST);
+ expected_order.push_back(TaskEvent::START);
+ expected_order.push_back(TaskEvent::END);
+
+ // This is O(n^2), but it runs fast enough currently so is not worth
+ // optimizing.
+ for (int i = 0; i < task_count; ++i) {
+ const std::vector<TaskEvent::Type> task_events =
+ GetEventsForTask(events, i);
+ if (task_events != expected_order) {
+ return ::testing::AssertionFailure()
+ << "Events for task " << i << " are out of order; expected: "
+ << ::testing::PrintToString(expected_order) << "; actual: "
+ << ::testing::PrintToString(task_events);
+ }
+ }
+ return ::testing::AssertionSuccess();
+}
+
+// Checks that no two tasks were running at the same time. I.e. the only
+// events allowed between the START and END of a task are the POSTs of other
+// tasks.
+::testing::AssertionResult CheckNoTaskRunsOverlap(
+ const std::vector<TaskEvent>& events) {
+ // If > -1, we're currently inside a START, END pair.
+ int current_task_i = -1;
+
+ std::vector<TaskEvent>::const_iterator event;
+ for (event = events.begin(); event != events.end(); ++event) {
+ bool spurious_event_found = false;
+
+ if (current_task_i == -1) { // Not inside a START, END pair.
+ switch (event->type) {
+ case TaskEvent::POST:
+ break;
+ case TaskEvent::START:
+ current_task_i = event->i;
+ break;
+ case TaskEvent::END:
+ spurious_event_found = true;
+ break;
+ }
+
+ } else { // Inside a START, END pair.
+ bool interleaved_task_detected = false;
+
+ switch (event->type) {
+ case TaskEvent::POST:
+ if (event->i == current_task_i)
+ spurious_event_found = true;
+ break;
+ case TaskEvent::START:
+ interleaved_task_detected = true;
+ break;
+ case TaskEvent::END:
+ if (event->i != current_task_i)
+ interleaved_task_detected = true;
+ else
+ current_task_i = -1;
+ break;
+ }
+
+ if (interleaved_task_detected) {
+ return ::testing::AssertionFailure()
+ << "Found event " << ::testing::PrintToString(*event)
+ << " between START and END events for task " << current_task_i
+ << "; event dump: " << ::testing::PrintToString(events);
+ }
+ }
+
+ if (spurious_event_found) {
+ const int event_i = event - events.begin();
+ return ::testing::AssertionFailure()
+ << "Spurious event " << ::testing::PrintToString(*event)
+ << " at position " << event_i << "; event dump: "
+ << ::testing::PrintToString(events);
+ }
+ }
+
+ return ::testing::AssertionSuccess();
+}
+
+} // namespace
+
+::testing::AssertionResult CheckNonNestableInvariants(
+ const std::vector<TaskEvent>& events,
+ int task_count) {
+ const std::vector<int> post_order =
+ GetEventTypeOrder(events, TaskEvent::POST);
+ const std::vector<int> start_order =
+ GetEventTypeOrder(events, TaskEvent::START);
+ const std::vector<int> end_order =
+ GetEventTypeOrder(events, TaskEvent::END);
+
+ if (start_order != post_order) {
+ return ::testing::AssertionFailure()
+ << "Expected START order (which equals actual POST order): \n"
+ << ::testing::PrintToString(post_order)
+ << "\n Actual START order:\n"
+ << ::testing::PrintToString(start_order);
+ }
+
+ if (end_order != post_order) {
+ return ::testing::AssertionFailure()
+ << "Expected END order (which equals actual POST order): \n"
+ << ::testing::PrintToString(post_order)
+ << "\n Actual END order:\n"
+ << ::testing::PrintToString(end_order);
+ }
+
+ const ::testing::AssertionResult result =
+ CheckEventOrdersForEachTask(events, task_count);
+ if (!result)
+ return result;
+
+ return CheckNoTaskRunsOverlap(events);
+}
+
+} // namespace internal
+
+} // namespace base
diff --git a/chromium/base/test/sequenced_task_runner_test_template.h b/chromium/base/test/sequenced_task_runner_test_template.h
new file mode 100644
index 00000000000..541ccae6727
--- /dev/null
+++ b/chromium/base/test/sequenced_task_runner_test_template.h
@@ -0,0 +1,350 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// SequencedTaskRunnerTest defines tests that implementations of
+// SequencedTaskRunner should pass in order to be conformant.
+// See task_runner_test_template.h for a description of how to use the
+// constructs in this file; these work the same.
+
+#ifndef BASE_TEST_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
+#define BASE_TEST_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
+
+#include <cstddef>
+#include <iosfwd>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace internal {
+
+struct TaskEvent {
+ enum Type { POST, START, END };
+ TaskEvent(int i, Type type);
+ int i;
+ Type type;
+};
+
+// Utility class used in the tests below.
+class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> {
+ public:
+ SequencedTaskTracker();
+
+ // Posts the non-nestable task |task|, and records its post event.
+ void PostWrappedNonNestableTask(SequencedTaskRunner* task_runner,
+ OnceClosure task);
+
+ // Posts the nestable task |task|, and records its post event.
+ void PostWrappedNestableTask(SequencedTaskRunner* task_runner,
+ OnceClosure task);
+
+ // Posts the delayed non-nestable task |task|, and records its post event.
+ void PostWrappedDelayedNonNestableTask(SequencedTaskRunner* task_runner,
+ OnceClosure task,
+ TimeDelta delay);
+
+ // Posts |task_count| non-nestable tasks.
+ void PostNonNestableTasks(SequencedTaskRunner* task_runner, int task_count);
+
+ const std::vector<TaskEvent>& GetTaskEvents() const;
+
+ // Returns after the tracker observes a total of |count| task completions.
+ void WaitForCompletedTasks(int count);
+
+ private:
+ friend class RefCountedThreadSafe<SequencedTaskTracker>;
+
+ ~SequencedTaskTracker();
+
+ // A task which runs |task|, recording the start and end events.
+ void RunTask(OnceClosure task, int task_i);
+
+ // Records a post event for task |i|. The owner is expected to be holding
+ // |lock_| (unlike |TaskStarted| and |TaskEnded|).
+ void TaskPosted(int i);
+
+ // Records a start event for task |i|.
+ void TaskStarted(int i);
+
+ // Records a end event for task |i|.
+ void TaskEnded(int i);
+
+ // Protects events_, next_post_i_, task_end_count_ and task_end_cv_.
+ Lock lock_;
+
+ // The events as they occurred for each task (protected by lock_).
+ std::vector<TaskEvent> events_;
+
+ // The ordinal to be used for the next task-posting task (protected by
+ // lock_).
+ int next_post_i_;
+
+ // The number of task end events we've received.
+ int task_end_count_;
+ ConditionVariable task_end_cv_;
+
+ DISALLOW_COPY_AND_ASSIGN(SequencedTaskTracker);
+};
+
+void PrintTo(const TaskEvent& event, std::ostream* os);
+
+// Checks the non-nestable task invariants for all tasks in |events|.
+//
+// The invariants are:
+// 1) Events started and ended in the same order that they were posted.
+// 2) Events for an individual tasks occur in the order {POST, START, END},
+// and there is only one instance of each event type for a task.
+// 3) The only events between a task's START and END events are the POSTs of
+// other tasks. I.e. tasks were run sequentially, not interleaved.
+::testing::AssertionResult CheckNonNestableInvariants(
+ const std::vector<TaskEvent>& events,
+ int task_count);
+
+} // namespace internal
+
+template <typename TaskRunnerTestDelegate>
+class SequencedTaskRunnerTest : public testing::Test {
+ protected:
+ SequencedTaskRunnerTest()
+ : task_tracker_(new internal::SequencedTaskTracker()) {}
+
+ const scoped_refptr<internal::SequencedTaskTracker> task_tracker_;
+ TaskRunnerTestDelegate delegate_;
+};
+
+TYPED_TEST_SUITE_P(SequencedTaskRunnerTest);
+
+// This test posts N non-nestable tasks in sequence, and expects them to run
+// in FIFO order, with no part of any two tasks' execution
+// overlapping. I.e. that each task starts only after the previously-posted
+// one has finished.
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNonNestable) {
+ const int kTaskCount = 1000;
+
+ this->delegate_.StartTaskRunner();
+ const scoped_refptr<SequencedTaskRunner> task_runner =
+ this->delegate_.GetTaskRunner();
+
+ this->task_tracker_->PostWrappedNonNestableTask(
+ task_runner.get(),
+ BindOnce(&PlatformThread::Sleep, TimeDelta::FromSeconds(1)));
+ for (int i = 1; i < kTaskCount; ++i) {
+ this->task_tracker_->PostWrappedNonNestableTask(task_runner.get(),
+ OnceClosure());
+ }
+
+ this->delegate_.StopTaskRunner();
+
+ EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+ kTaskCount));
+}
+
+// This test posts N nestable tasks in sequence. It has the same expectations
+// as SequentialNonNestable because even though the tasks are nestable, they
+// will not be run nestedly in this case.
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNestable) {
+ const int kTaskCount = 1000;
+
+ this->delegate_.StartTaskRunner();
+ const scoped_refptr<SequencedTaskRunner> task_runner =
+ this->delegate_.GetTaskRunner();
+
+ this->task_tracker_->PostWrappedNestableTask(
+ task_runner.get(),
+ BindOnce(&PlatformThread::Sleep, TimeDelta::FromSeconds(1)));
+ for (int i = 1; i < kTaskCount; ++i) {
+ this->task_tracker_->PostWrappedNestableTask(task_runner.get(),
+ OnceClosure());
+ }
+
+ this->delegate_.StopTaskRunner();
+
+ EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+ kTaskCount));
+}
+
+// This test posts non-nestable tasks in order of increasing delay, and checks
+// that that the tasks are run in FIFO order and that there is no execution
+// overlap whatsoever between any two tasks.
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialDelayedNonNestable) {
+ const int kTaskCount = 20;
+ const int kDelayIncrementMs = 50;
+
+ this->delegate_.StartTaskRunner();
+ const scoped_refptr<SequencedTaskRunner> task_runner =
+ this->delegate_.GetTaskRunner();
+
+ for (int i = 0; i < kTaskCount; ++i) {
+ this->task_tracker_->PostWrappedDelayedNonNestableTask(
+ task_runner.get(), OnceClosure(),
+ TimeDelta::FromMilliseconds(kDelayIncrementMs * i));
+ }
+
+ this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+ this->delegate_.StopTaskRunner();
+
+ EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+ kTaskCount));
+}
+
+// This test posts a fast, non-nestable task from within each of a number of
+// slow, non-nestable tasks and checks that they all run in the sequence they
+// were posted in and that there is no execution overlap whatsoever.
+TYPED_TEST_P(SequencedTaskRunnerTest, NonNestablePostFromNonNestableTask) {
+ const int kParentCount = 10;
+ const int kChildrenPerParent = 10;
+
+ this->delegate_.StartTaskRunner();
+ const scoped_refptr<SequencedTaskRunner> task_runner =
+ this->delegate_.GetTaskRunner();
+
+ for (int i = 0; i < kParentCount; ++i) {
+ auto task = BindOnce(&internal::SequencedTaskTracker::PostNonNestableTasks,
+ this->task_tracker_, RetainedRef(task_runner),
+ kChildrenPerParent);
+ this->task_tracker_->PostWrappedNonNestableTask(task_runner.get(),
+ std::move(task));
+ }
+
+ this->delegate_.StopTaskRunner();
+
+ EXPECT_TRUE(CheckNonNestableInvariants(
+ this->task_tracker_->GetTaskEvents(),
+ kParentCount * (kChildrenPerParent + 1)));
+}
+
+// This test posts two tasks with the same delay, and checks that the tasks are
+// run in the order in which they were posted.
+//
+// NOTE: This is actually an approximate test since the API only takes a
+// "delay" parameter, so we are not exactly simulating two tasks that get
+// posted at the exact same time. It would be nice if the API allowed us to
+// specify the desired run time.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTasksSameDelay) {
+ const int kTaskCount = 2;
+ const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+ this->delegate_.StartTaskRunner();
+ const scoped_refptr<SequencedTaskRunner> task_runner =
+ this->delegate_.GetTaskRunner();
+
+ this->task_tracker_->PostWrappedDelayedNonNestableTask(task_runner.get(),
+ OnceClosure(), kDelay);
+ this->task_tracker_->PostWrappedDelayedNonNestableTask(task_runner.get(),
+ OnceClosure(), kDelay);
+ this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+ this->delegate_.StopTaskRunner();
+
+ EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+ kTaskCount));
+}
+
+// This test posts a normal task and a delayed task, and checks that the
+// delayed task runs after the normal task even if the normal task takes
+// a long time to run.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskAfterLongTask) {
+ const int kTaskCount = 2;
+
+ this->delegate_.StartTaskRunner();
+ const scoped_refptr<SequencedTaskRunner> task_runner =
+ this->delegate_.GetTaskRunner();
+
+ this->task_tracker_->PostWrappedNonNestableTask(
+ task_runner.get(),
+ base::BindOnce(&PlatformThread::Sleep, TimeDelta::FromMilliseconds(50)));
+ this->task_tracker_->PostWrappedDelayedNonNestableTask(
+ task_runner.get(), OnceClosure(), TimeDelta::FromMilliseconds(10));
+ this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+ this->delegate_.StopTaskRunner();
+
+ EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+ kTaskCount));
+}
+
+// Test that a pile of normal tasks and a delayed task run in the
+// time-to-run order.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskAfterManyLongTasks) {
+ const int kTaskCount = 11;
+
+ this->delegate_.StartTaskRunner();
+ const scoped_refptr<SequencedTaskRunner> task_runner =
+ this->delegate_.GetTaskRunner();
+
+ for (int i = 0; i < kTaskCount - 1; i++) {
+ this->task_tracker_->PostWrappedNonNestableTask(
+ task_runner.get(), base::BindOnce(&PlatformThread::Sleep,
+ TimeDelta::FromMilliseconds(50)));
+ }
+ this->task_tracker_->PostWrappedDelayedNonNestableTask(
+ task_runner.get(), OnceClosure(), TimeDelta::FromMilliseconds(10));
+ this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+ this->delegate_.StopTaskRunner();
+
+ EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+ kTaskCount));
+}
+
+
+// TODO(francoisk777@gmail.com) Add a test, similiar to the above, which runs
+// some tasked nestedly (which should be implemented in the test
+// delegate). Also add, to the the test delegate, a predicate which checks
+// whether the implementation supports nested tasks.
+//
+
+// The SequencedTaskRunnerTest test case verifies behaviour that is expected
+// from a sequenced task runner in order to be conformant.
+REGISTER_TYPED_TEST_SUITE_P(SequencedTaskRunnerTest,
+ SequentialNonNestable,
+ SequentialNestable,
+ SequentialDelayedNonNestable,
+ NonNestablePostFromNonNestableTask,
+ DelayedTasksSameDelay,
+ DelayedTaskAfterLongTask,
+ DelayedTaskAfterManyLongTasks);
+
+template <typename TaskRunnerTestDelegate>
+class SequencedTaskRunnerDelayedTest
+ : public SequencedTaskRunnerTest<TaskRunnerTestDelegate> {};
+
+TYPED_TEST_SUITE_P(SequencedTaskRunnerDelayedTest);
+
+// This test posts a delayed task, and checks that the task is run later than
+// the specified time.
+TYPED_TEST_P(SequencedTaskRunnerDelayedTest, DelayedTaskBasic) {
+ const int kTaskCount = 1;
+ const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+ this->delegate_.StartTaskRunner();
+ const scoped_refptr<SequencedTaskRunner> task_runner =
+ this->delegate_.GetTaskRunner();
+
+ Time time_before_run = Time::Now();
+ this->task_tracker_->PostWrappedDelayedNonNestableTask(task_runner.get(),
+ OnceClosure(), kDelay);
+ this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+ this->delegate_.StopTaskRunner();
+ Time time_after_run = Time::Now();
+
+ EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+ kTaskCount));
+ EXPECT_LE(kDelay, time_after_run - time_before_run);
+}
+
+// SequencedTaskRunnerDelayedTest tests that the |delay| parameter of
+// is used to actually wait for |delay| ms before executing the task.
+// This is not mandatory for a SequencedTaskRunner to be compliant.
+REGISTER_TYPED_TEST_SUITE_P(SequencedTaskRunnerDelayedTest, DelayedTaskBasic);
+
+} // namespace base
+
+#endif // BASE_TEST_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
diff --git a/chromium/base/test/simple_test_clock.cc b/chromium/base/test/simple_test_clock.cc
new file mode 100644
index 00000000000..7486d793581
--- /dev/null
+++ b/chromium/base/test/simple_test_clock.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/simple_test_clock.h"
+
+namespace base {
+
+SimpleTestClock::SimpleTestClock() = default;
+
+SimpleTestClock::~SimpleTestClock() = default;
+
+Time SimpleTestClock::Now() const {
+ AutoLock lock(lock_);
+ return now_;
+}
+
+void SimpleTestClock::Advance(TimeDelta delta) {
+ AutoLock lock(lock_);
+ now_ += delta;
+}
+
+void SimpleTestClock::SetNow(Time now) {
+ AutoLock lock(lock_);
+ now_ = now;
+}
+
+} // namespace base
diff --git a/chromium/base/test/simple_test_clock.h b/chromium/base/test/simple_test_clock.h
new file mode 100644
index 00000000000..0cbcf082632
--- /dev/null
+++ b/chromium/base/test/simple_test_clock.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SIMPLE_TEST_CLOCK_H_
+#define BASE_TEST_SIMPLE_TEST_CLOCK_H_
+
+#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "base/time/clock.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// SimpleTestClock is a Clock implementation that gives control over
+// the returned Time objects. All methods may be called from any
+// thread.
+class SimpleTestClock : public Clock {
+ public:
+ // Starts off with a clock set to Time().
+ SimpleTestClock();
+ ~SimpleTestClock() override;
+
+ Time Now() const override;
+
+ // Advances the clock by |delta|.
+ void Advance(TimeDelta delta);
+
+ // Sets the clock to the given time.
+ void SetNow(Time now);
+
+ private:
+ // Protects |now_|.
+ mutable Lock lock_;
+
+ Time now_;
+};
+
+} // namespace base
+
+#endif // BASE_TEST_SIMPLE_TEST_CLOCK_H_
diff --git a/chromium/base/test/simple_test_tick_clock.cc b/chromium/base/test/simple_test_tick_clock.cc
new file mode 100644
index 00000000000..3efeaceeef5
--- /dev/null
+++ b/chromium/base/test/simple_test_tick_clock.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/simple_test_tick_clock.h"
+
+#include "base/check.h"
+
+namespace base {
+
+SimpleTestTickClock::SimpleTestTickClock() = default;
+
+SimpleTestTickClock::~SimpleTestTickClock() = default;
+
+TimeTicks SimpleTestTickClock::NowTicks() const {
+ AutoLock lock(lock_);
+ return now_ticks_;
+}
+
+void SimpleTestTickClock::Advance(TimeDelta delta) {
+ AutoLock lock(lock_);
+ DCHECK(delta >= TimeDelta());
+ now_ticks_ += delta;
+}
+
+void SimpleTestTickClock::SetNowTicks(TimeTicks ticks) {
+ AutoLock lock(lock_);
+ now_ticks_ = ticks;
+}
+
+} // namespace base
diff --git a/chromium/base/test/simple_test_tick_clock.h b/chromium/base/test/simple_test_tick_clock.h
new file mode 100644
index 00000000000..923eba4a9af
--- /dev/null
+++ b/chromium/base/test/simple_test_tick_clock.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SIMPLE_TEST_TICK_CLOCK_H_
+#define BASE_TEST_SIMPLE_TEST_TICK_CLOCK_H_
+
+#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// SimpleTestTickClock is a TickClock implementation that gives
+// control over the returned TimeTicks objects. All methods may be
+// called from any thread.
+class SimpleTestTickClock : public TickClock {
+ public:
+ // Starts off with a clock set to TimeTicks().
+ SimpleTestTickClock();
+ ~SimpleTestTickClock() override;
+
+ TimeTicks NowTicks() const override;
+
+ // Advances the clock by |delta|, which must not be negative.
+ void Advance(TimeDelta delta);
+
+ // Sets the clock to the given time.
+ void SetNowTicks(TimeTicks ticks);
+
+ private:
+ // Protects |now_ticks_|.
+ mutable Lock lock_;
+
+ TimeTicks now_ticks_;
+};
+
+} // namespace base
+
+#endif // BASE_TEST_SIMPLE_TEST_TICK_CLOCK_H_
diff --git a/chromium/base/test/spin_wait.h b/chromium/base/test/spin_wait.h
new file mode 100644
index 00000000000..42b3b3510f1
--- /dev/null
+++ b/chromium/base/test/spin_wait.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file provides a macro ONLY for use in testing.
+// DO NOT USE IN PRODUCTION CODE. There are much better ways to wait.
+
+// This code is very helpful in testing multi-threaded code, without depending
+// on almost any primitives. This is especially helpful if you are testing
+// those primitive multi-threaded constructs.
+
+// We provide a simple one argument spin wait (for 1 second), and a generic
+// spin wait (for longer periods of time).
+
+#ifndef BASE_TEST_SPIN_WAIT_H_
+#define BASE_TEST_SPIN_WAIT_H_
+
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+
+// Provide a macro that will wait no longer than 1 second for an asynchronous
+// change is the value of an expression.
+// A typical use would be:
+//
+// SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 == f(x));
+//
+// The expression will be evaluated repeatedly until it is true, or until
+// the time (1 second) expires.
+// Since tests generally have a 5 second watch dog timer, this spin loop is
+// typically used to get the padding needed on a given test platform to assure
+// that the test passes, even if load varies, and external events vary.
+
+#define SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(expression) \
+ SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(base::TimeDelta::FromSeconds(1), \
+ (expression))
+
+#define SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(delta, expression) \
+ do { \
+ base::TimeTicks spin_wait_start = base::TimeTicks::Now(); \
+ const base::TimeDelta kSpinWaitTimeout = delta; \
+ while (!(expression)) { \
+ if (kSpinWaitTimeout < base::TimeTicks::Now() - spin_wait_start) { \
+ EXPECT_LE((base::TimeTicks::Now() - spin_wait_start).InMilliseconds(), \
+ kSpinWaitTimeout.InMilliseconds()) \
+ << "Timed out"; \
+ break; \
+ } \
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); \
+ } \
+ } while (0)
+
+#endif // BASE_TEST_SPIN_WAIT_H_
diff --git a/chromium/base/test/task_environment.cc b/chromium/base/test/task_environment.cc
new file mode 100644
index 00000000000..e8aa5d502a5
--- /dev/null
+++ b/chromium/base/test/task_environment.cc
@@ -0,0 +1,808 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/task_environment.h"
+
+#include <algorithm>
+#include <memory>
+
+#include "base/bind_helpers.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_pump.h"
+#include "base/message_loop/message_pump_type.h"
+#include "base/no_destructor.h"
+#include "base/run_loop.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/task/post_task.h"
+#include "base/task/sequence_manager/sequence_manager_impl.h"
+#include "base/task/sequence_manager/time_domain.h"
+#include "base/task/simple_task_executor.h"
+#include "base/task/thread_pool/thread_pool_impl.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/test/test_timeouts.h"
+#include "base/thread_annotations.h"
+#include "base/threading/sequence_local_storage_map.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/clock.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+#include "base/time/time_override.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#include "base/files/file_descriptor_watcher_posix.h"
+#endif
+
+namespace base {
+namespace test {
+
+namespace {
+
+ObserverList<TaskEnvironment::DestructionObserver>& GetDestructionObservers() {
+ static NoDestructor<ObserverList<TaskEnvironment::DestructionObserver>>
+ instance;
+ return *instance;
+}
+
+base::MessagePumpType GetMessagePumpTypeForMainThreadType(
+ TaskEnvironment::MainThreadType main_thread_type) {
+ switch (main_thread_type) {
+ case TaskEnvironment::MainThreadType::DEFAULT:
+ return MessagePumpType::DEFAULT;
+ case TaskEnvironment::MainThreadType::UI:
+ return MessagePumpType::UI;
+ case TaskEnvironment::MainThreadType::IO:
+ return MessagePumpType::IO;
+ }
+ NOTREACHED();
+ return MessagePumpType::DEFAULT;
+}
+
+std::unique_ptr<sequence_manager::SequenceManager>
+CreateSequenceManagerForMainThreadType(
+ TaskEnvironment::MainThreadType main_thread_type) {
+ auto type = GetMessagePumpTypeForMainThreadType(main_thread_type);
+ return sequence_manager::CreateSequenceManagerOnCurrentThreadWithPump(
+ MessagePump::Create(type),
+ base::sequence_manager::SequenceManager::Settings::Builder()
+ .SetMessagePumpType(type)
+ .Build());
+}
+
+class TickClockBasedClock : public Clock {
+ public:
+ explicit TickClockBasedClock(const TickClock* tick_clock)
+ : tick_clock_(*tick_clock),
+ start_ticks_(tick_clock_.NowTicks()),
+ start_time_(Time::UnixEpoch()) {}
+
+ Time Now() const override {
+ return start_time_ + (tick_clock_.NowTicks() - start_ticks_);
+ }
+
+ private:
+ const TickClock& tick_clock_;
+ const TimeTicks start_ticks_;
+ const Time start_time_;
+};
+
+} // namespace
+
+class TaskEnvironment::TestTaskTracker
+ : public internal::ThreadPoolImpl::TaskTrackerImpl {
+ public:
+ TestTaskTracker();
+
+ // Allow running tasks. Returns whether tasks were previously allowed to run.
+ bool AllowRunTasks();
+
+ // Disallow running tasks. Returns true on success; success requires there to
+ // be no tasks currently running. Returns false if >0 tasks are currently
+ // running. Prior to returning false, it will attempt to block until at least
+ // one task has completed (in an attempt to avoid callers busy-looping
+ // DisallowRunTasks() calls with the same set of slowly ongoing tasks). This
+ // block attempt will also have a short timeout (in an attempt to prevent the
+ // fallout of blocking: if the only task remaining is blocked on the main
+ // thread, waiting for it to complete results in a deadlock...).
+ bool DisallowRunTasks();
+
+ // Returns true if tasks are currently allowed to run.
+ bool TasksAllowedToRun() const;
+
+ private:
+ friend class TaskEnvironment;
+
+ // internal::ThreadPoolImpl::TaskTrackerImpl:
+ void RunTask(internal::Task task,
+ internal::TaskSource* sequence,
+ const TaskTraits& traits) override;
+
+ // Synchronizes accesses to members below.
+ mutable Lock lock_;
+
+ // True if running tasks is allowed.
+ bool can_run_tasks_ GUARDED_BY(lock_) = true;
+
+ // Signaled when |can_run_tasks_| becomes true.
+ ConditionVariable can_run_tasks_cv_ GUARDED_BY(lock_);
+
+ // Signaled when a task is completed.
+ ConditionVariable task_completed_cv_ GUARDED_BY(lock_);
+
+ // Number of tasks that are currently running.
+ int num_tasks_running_ GUARDED_BY(lock_) = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(TestTaskTracker);
+};
+
+class TaskEnvironment::MockTimeDomain : public sequence_manager::TimeDomain,
+ public TickClock {
+ public:
+ explicit MockTimeDomain(sequence_manager::SequenceManager* sequence_manager)
+ : sequence_manager_(sequence_manager) {
+ DCHECK_EQ(nullptr, current_mock_time_domain_);
+ current_mock_time_domain_ = this;
+ }
+
+ ~MockTimeDomain() override {
+ DCHECK_EQ(this, current_mock_time_domain_);
+ current_mock_time_domain_ = nullptr;
+ }
+
+ static MockTimeDomain* current_mock_time_domain_;
+
+ static Time GetTime() {
+ return Time::UnixEpoch() + (current_mock_time_domain_->Now() - TimeTicks());
+ }
+
+ static TimeTicks GetTimeTicks() { return current_mock_time_domain_->Now(); }
+
+ using TimeDomain::NextScheduledRunTime;
+
+ Optional<TimeTicks> NextScheduledRunTime() const {
+ // The TimeDomain doesn't know about immediate tasks, check if we have any.
+ if (!sequence_manager_->IsIdleForTesting())
+ return Now();
+ return TimeDomain::NextScheduledRunTime();
+ }
+
+ void AdvanceClock(TimeDelta delta) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ {
+ AutoLock lock(now_ticks_lock_);
+ now_ticks_ += delta;
+ }
+ if (thread_pool_)
+ thread_pool_->ProcessRipeDelayedTasksForTesting();
+ }
+
+ static std::unique_ptr<TaskEnvironment::MockTimeDomain> CreateAndRegister(
+ sequence_manager::SequenceManager* sequence_manager) {
+ auto mock_time_domain =
+ std::make_unique<TaskEnvironment::MockTimeDomain>(sequence_manager);
+ sequence_manager->RegisterTimeDomain(mock_time_domain.get());
+ return mock_time_domain;
+ }
+
+ void SetThreadPool(internal::ThreadPoolImpl* thread_pool,
+ const TestTaskTracker* thread_pool_task_tracker) {
+ DCHECK(!thread_pool_);
+ DCHECK(!thread_pool_task_tracker_);
+ thread_pool_ = thread_pool;
+ thread_pool_task_tracker_ = thread_pool_task_tracker;
+ }
+
+ // sequence_manager::TimeDomain:
+
+ sequence_manager::LazyNow CreateLazyNow() const override {
+ AutoLock lock(now_ticks_lock_);
+ return sequence_manager::LazyNow(now_ticks_);
+ }
+
+ TimeTicks Now() const override {
+ // This can be called from any thread.
+ AutoLock lock(now_ticks_lock_);
+ return now_ticks_;
+ }
+
+ Optional<TimeDelta> DelayTillNextTask(
+ sequence_manager::LazyNow* lazy_now) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ // Make sure TimeDomain::NextScheduledRunTime has taken canceled tasks into
+ // account, ReclaimMemory sweeps canceled delayed tasks.
+ sequence_manager()->ReclaimMemory();
+ Optional<TimeTicks> run_time = NextScheduledRunTime();
+ // Check if we've run out of tasks.
+ if (!run_time)
+ return base::nullopt;
+
+ // Check if we have a task that should be running now. Reading |now_ticks_|
+ // from the main thread doesn't require the lock.
+ if (run_time <= TS_UNCHECKED_READ(now_ticks_))
+ return base::TimeDelta();
+
+ // The next task is a future delayed task. Since we're using mock time, we
+ // don't want an actual OS level delayed wake up scheduled, so pretend we
+ // have no more work. This will result in appearing idle, TaskEnvironment
+ // will decide what to do based on that (return to caller or fast-forward
+ // time).
+ return base::nullopt;
+ }
+
+ // This method is called when the underlying message pump has run out of
+ // non-delayed work. Advances time to the next task unless
+ // |quit_when_idle_requested| or TaskEnvironment controls mock time.
+ bool MaybeFastForwardToNextTask(bool quit_when_idle_requested) override {
+ if (quit_when_idle_requested)
+ return false;
+
+ return FastForwardToNextTaskOrCap(TimeTicks::Max()) ==
+ NextTaskSource::kMainThread;
+ }
+
+ const char* GetName() const override { return "MockTimeDomain"; }
+
+ // TickClock implementation:
+ TimeTicks NowTicks() const override { return Now(); }
+
+ // Used by FastForwardToNextTaskOrCap() to return which task source time was
+ // advanced to.
+ enum class NextTaskSource {
+ // Out of tasks under |fast_forward_cap|.
+ kNone,
+ // There's now >=1 immediate task on the main thread.
+ kMainThread,
+ // There's now >=1 immediate task in the thread pool.
+ kThreadPool,
+ };
+
+ // Advances time to the first of : next main thread task, next thread pool
+ // task, or |fast_forward_cap| (if it's not Max()).
+ NextTaskSource FastForwardToNextTaskOrCap(TimeTicks fast_forward_cap) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ // We don't need to call ReclaimMemory here because
+ // DelayTillNextTask will have dealt with cancelled delayed tasks for us.
+ Optional<TimeTicks> next_main_thread_task_time = NextScheduledRunTime();
+
+ // Consider the next thread pool tasks iff they're running.
+ Optional<TimeTicks> next_thread_pool_task_time;
+ if (thread_pool_ && thread_pool_task_tracker_->TasksAllowedToRun()) {
+ next_thread_pool_task_time =
+ thread_pool_->NextScheduledRunTimeForTesting();
+ }
+
+ // Custom comparison logic to consider nullopt the largest rather than
+ // smallest value. Could consider using TimeTicks::Max() instead of nullopt
+ // to represent out-of-tasks?
+ Optional<TimeTicks> next_task_time;
+ if (!next_main_thread_task_time) {
+ next_task_time = next_thread_pool_task_time;
+ } else if (!next_thread_pool_task_time) {
+ next_task_time = next_main_thread_task_time;
+ } else {
+ next_task_time =
+ std::min(*next_main_thread_task_time, *next_thread_pool_task_time);
+ }
+
+ if (next_task_time && *next_task_time <= fast_forward_cap) {
+ {
+ AutoLock lock(now_ticks_lock_);
+ // It's possible for |next_task_time| to be in the past in the following
+ // scenario:
+ // Start with Now() == 100ms
+ // Thread A : Post 200ms delayed task T (construct and enqueue)
+ // Thread B : Construct 20ms delayed task U
+ // => |delayed_run_time| == 120ms.
+ // Thread A : FastForwardToNextTaskOrCap() => fast-forwards to T @
+ // 300ms (task U is not yet in queue).
+ // Thread B : Complete enqueue of task U.
+ // Thread A : FastForwardToNextTaskOrCap() => must stay at 300ms and run
+ // U, not go back to 120ms.
+ // Hence we need std::max() to protect again this because construction
+ // and enqueuing isn't atomic in time (LazyNow support in
+ // base/task/thread_pool could help).
+ now_ticks_ = std::max(now_ticks_, *next_task_time);
+ }
+
+ if (next_task_time == next_thread_pool_task_time) {
+ // Let the thread pool know that it should post its now ripe delayed
+ // tasks.
+ thread_pool_->ProcessRipeDelayedTasksForTesting();
+ return NextTaskSource::kThreadPool;
+ }
+ return NextTaskSource::kMainThread;
+ }
+
+ if (!fast_forward_cap.is_max()) {
+ AutoLock lock(now_ticks_lock_);
+ // It's possible that Now() is already beyond |fast_forward_cap| when the
+ // caller nests multiple FastForwardBy() calls.
+ now_ticks_ = std::max(now_ticks_, fast_forward_cap);
+ }
+
+ return NextTaskSource::kNone;
+ }
+
+ private:
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ sequence_manager::SequenceManager* const sequence_manager_;
+
+ internal::ThreadPoolImpl* thread_pool_ = nullptr;
+ const TestTaskTracker* thread_pool_task_tracker_ = nullptr;
+
+ // Protects |now_ticks_|
+ mutable Lock now_ticks_lock_;
+
+ // Only ever written to from the main sequence. Start from real Now() instead
+ // of zero to give a more realistic view to tests.
+ TimeTicks now_ticks_ GUARDED_BY(now_ticks_lock_){
+ base::subtle::TimeTicksNowIgnoringOverride()};
+};
+
+TaskEnvironment::MockTimeDomain*
+ TaskEnvironment::MockTimeDomain::current_mock_time_domain_ = nullptr;
+
+TaskEnvironment::TaskEnvironment(
+ TimeSource time_source,
+ MainThreadType main_thread_type,
+ ThreadPoolExecutionMode thread_pool_execution_mode,
+ ThreadingMode threading_mode,
+ ThreadPoolCOMEnvironment thread_pool_com_environment,
+ bool subclass_creates_default_taskrunner,
+ trait_helpers::NotATraitTag)
+ : main_thread_type_(main_thread_type),
+ thread_pool_execution_mode_(thread_pool_execution_mode),
+ threading_mode_(threading_mode),
+ thread_pool_com_environment_(thread_pool_com_environment),
+ subclass_creates_default_taskrunner_(subclass_creates_default_taskrunner),
+ sequence_manager_(
+ CreateSequenceManagerForMainThreadType(main_thread_type)),
+ mock_time_domain_(
+ time_source != TimeSource::SYSTEM_TIME
+ ? MockTimeDomain::CreateAndRegister(sequence_manager_.get())
+ : nullptr),
+ time_overrides_(time_source == TimeSource::MOCK_TIME
+ ? std::make_unique<subtle::ScopedTimeClockOverrides>(
+ &MockTimeDomain::GetTime,
+ &MockTimeDomain::GetTimeTicks,
+ nullptr)
+ : nullptr),
+ mock_clock_(mock_time_domain_ ? std::make_unique<TickClockBasedClock>(
+ mock_time_domain_.get())
+ : nullptr),
+ scoped_lazy_task_runner_list_for_testing_(
+ std::make_unique<internal::ScopedLazyTaskRunnerListForTesting>()),
+ // TODO(https://crbug.com/922098): Enable Run() timeouts even for
+ // instances created with TimeSource::MOCK_TIME.
+ run_loop_timeout_(
+ mock_time_domain_
+ ? nullptr
+ : std::make_unique<ScopedRunLoopTimeout>(
+ FROM_HERE,
+ TestTimeouts::action_timeout(),
+ BindRepeating(&sequence_manager::SequenceManager::
+ DescribeAllPendingTasks,
+ Unretained(sequence_manager_.get())))) {
+ CHECK(!base::ThreadTaskRunnerHandle::IsSet());
+ // If |subclass_creates_default_taskrunner| is true then initialization is
+ // deferred until DeferredInitFromSubclass().
+ if (!subclass_creates_default_taskrunner) {
+ task_queue_ = sequence_manager_->CreateTaskQueue(
+ sequence_manager::TaskQueue::Spec("task_environment_default")
+ .SetTimeDomain(mock_time_domain_.get()));
+ task_runner_ = task_queue_->task_runner();
+ sequence_manager_->SetDefaultTaskRunner(task_runner_);
+ simple_task_executor_ = std::make_unique<SimpleTaskExecutor>(task_runner_);
+ CHECK(base::ThreadTaskRunnerHandle::IsSet())
+ << "ThreadTaskRunnerHandle should've been set now.";
+ CompleteInitialization();
+ }
+
+ if (threading_mode_ != ThreadingMode::MAIN_THREAD_ONLY)
+ InitializeThreadPool();
+
+ if (thread_pool_execution_mode_ == ThreadPoolExecutionMode::QUEUED &&
+ task_tracker_) {
+ CHECK(task_tracker_->DisallowRunTasks());
+ }
+}
+
+void TaskEnvironment::InitializeThreadPool() {
+ CHECK(!ThreadPoolInstance::Get())
+ << "Someone has already installed a ThreadPoolInstance. If nothing in "
+ "your test does so, then a test that ran earlier may have installed "
+ "one and leaked it. base::TestSuite will trap leaked globals, unless "
+ "someone has explicitly disabled it with "
+ "DisableCheckForLeakedGlobals().";
+
+ ThreadPoolInstance::InitParams init_params(kNumForegroundThreadPoolThreads);
+ init_params.suggested_reclaim_time = TimeDelta::Max();
+#if defined(OS_WIN)
+ if (thread_pool_com_environment_ == ThreadPoolCOMEnvironment::COM_MTA) {
+ init_params.common_thread_pool_environment =
+ ThreadPoolInstance::InitParams::CommonThreadPoolEnvironment::COM_MTA;
+ }
+#endif
+
+ auto task_tracker = std::make_unique<TestTaskTracker>();
+ task_tracker_ = task_tracker.get();
+ auto thread_pool = std::make_unique<internal::ThreadPoolImpl>(
+ std::string(), std::move(task_tracker));
+ if (mock_time_domain_)
+ mock_time_domain_->SetThreadPool(thread_pool.get(), task_tracker_);
+ ThreadPoolInstance::Set(std::move(thread_pool));
+ ThreadPoolInstance::Get()->Start(init_params);
+}
+
+void TaskEnvironment::CompleteInitialization() {
+ DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+ if (main_thread_type() == MainThreadType::IO) {
+ file_descriptor_watcher_ =
+ std::make_unique<FileDescriptorWatcher>(GetMainThreadTaskRunner());
+ }
+#endif // defined(OS_POSIX) || defined(OS_FUCHSIA)
+}
+
+TaskEnvironment::TaskEnvironment(TaskEnvironment&& other) = default;
+
+TaskEnvironment::~TaskEnvironment() {
+ DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+
+ // If we've been moved then bail out.
+ if (!owns_instance_)
+ return;
+ for (auto& observer : GetDestructionObservers())
+ observer.WillDestroyCurrentTaskEnvironment();
+ DestroyThreadPool();
+ task_queue_ = nullptr;
+ NotifyDestructionObserversAndReleaseSequenceManager();
+}
+
+void TaskEnvironment::DestroyThreadPool() {
+ DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+
+ if (threading_mode_ == ThreadingMode::MAIN_THREAD_ONLY)
+ return;
+
+ // Ideally this would RunLoop().RunUntilIdle() here to catch any errors or
+ // infinite post loop in the remaining work but this isn't possible right now
+ // because base::~MessageLoop() didn't use to do this and adding it here would
+ // make the migration away from MessageLoop that much harder.
+
+ // Without FlushForTesting(), DeleteSoon() and ReleaseSoon() tasks could be
+ // skipped, resulting in memory leaks.
+ task_tracker_->AllowRunTasks();
+ ThreadPoolInstance::Get()->FlushForTesting();
+ ThreadPoolInstance::Get()->Shutdown();
+ ThreadPoolInstance::Get()->JoinForTesting();
+ // Destroying ThreadPoolInstance state can result in waiting on worker
+ // threads. Make sure this is allowed to avoid flaking tests that have
+ // disallowed waits on their main thread.
+ ScopedAllowBaseSyncPrimitivesForTesting allow_waits_to_destroy_task_tracker;
+ ThreadPoolInstance::Set(nullptr);
+}
+
+sequence_manager::TimeDomain* TaskEnvironment::GetTimeDomain() const {
+ return mock_time_domain_ ? mock_time_domain_.get()
+ : sequence_manager_->GetRealTimeDomain();
+}
+
+sequence_manager::SequenceManager* TaskEnvironment::sequence_manager() const {
+ DCHECK(subclass_creates_default_taskrunner_);
+ return sequence_manager_.get();
+}
+
+void TaskEnvironment::DeferredInitFromSubclass(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+
+ task_runner_ = std::move(task_runner);
+ sequence_manager_->SetDefaultTaskRunner(task_runner_);
+ CompleteInitialization();
+}
+
+void TaskEnvironment::NotifyDestructionObserversAndReleaseSequenceManager() {
+ DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+
+ // A derived classes may call this method early.
+ if (!sequence_manager_)
+ return;
+
+ if (mock_time_domain_)
+ sequence_manager_->UnregisterTimeDomain(mock_time_domain_.get());
+
+ sequence_manager_.reset();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+TaskEnvironment::GetMainThreadTaskRunner() {
+ DCHECK(task_runner_);
+ return task_runner_;
+}
+
+bool TaskEnvironment::MainThreadIsIdle() const {
+ DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+
+ sequence_manager::internal::SequenceManagerImpl* sequence_manager_impl =
+ static_cast<sequence_manager::internal::SequenceManagerImpl*>(
+ sequence_manager_.get());
+ // ReclaimMemory sweeps canceled delayed tasks.
+ sequence_manager_impl->ReclaimMemory();
+ return sequence_manager_impl->IsIdleForTesting();
+}
+
+void TaskEnvironment::RunUntilIdle() {
+ DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+
+ if (threading_mode_ == ThreadingMode::MAIN_THREAD_ONLY) {
+ RunLoop(RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
+ return;
+ }
+
+ // TODO(gab): This can be heavily simplified to essentially:
+ // bool HasMainThreadTasks() {
+ // if (message_loop_)
+ // return !message_loop_->IsIdleForTesting();
+ // return mock_time_task_runner_->NextPendingTaskDelay().is_zero();
+ // }
+ // while (task_tracker_->HasIncompleteTasks() || HasMainThreadTasks()) {
+ // base::RunLoop().RunUntilIdle();
+ // // Avoid busy-looping.
+ // if (task_tracker_->HasIncompleteTasks())
+ // PlatformThread::Sleep(TimeDelta::FromMilliSeconds(1));
+ // }
+ // Update: This can likely be done now that MessageLoop::IsIdleForTesting()
+ // checks all queues.
+ //
+ // Other than that it works because once |task_tracker_->HasIncompleteTasks()|
+ // is false we know for sure that the only thing that can make it true is a
+ // main thread task (TaskEnvironment owns all the threads). As such we can't
+ // racily see it as false on the main thread and be wrong as if it the main
+ // thread sees the atomic count at zero, it's the only one that can make it go
+ // up. And the only thing that can make it go up on the main thread are main
+ // thread tasks and therefore we're done if there aren't any left.
+ //
+ // This simplification further allows simplification of DisallowRunTasks().
+ //
+ // This can also be simplified even further once TaskTracker becomes directly
+ // aware of main thread tasks. https://crbug.com/660078.
+
+ const bool could_run_tasks = task_tracker_->AllowRunTasks();
+
+ for (;;) {
+ task_tracker_->AllowRunTasks();
+
+ // First run as many tasks as possible on the main thread in parallel with
+ // tasks in ThreadPool. This increases likelihood of TSAN catching
+ // threading errors and eliminates possibility of hangs should a
+ // ThreadPool task synchronously block on a main thread task
+ // (ThreadPoolInstance::FlushForTesting() can't be used here for that
+ // reason).
+ RunLoop(RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
+
+ // Then halt ThreadPool. DisallowRunTasks() failing indicates that there
+ // were ThreadPool tasks currently running. In that case, try again from
+ // top when DisallowRunTasks() yields control back to this thread as they
+ // may have posted main thread tasks.
+ if (!task_tracker_->DisallowRunTasks())
+ continue;
+
+ // Once ThreadPool is halted. Run any remaining main thread tasks (which
+ // may have been posted by ThreadPool tasks that completed between the
+ // above main thread RunUntilIdle() and ThreadPool DisallowRunTasks()).
+ // Note: this assumes that no main thread task synchronously blocks on a
+ // ThreadPool tasks (it certainly shouldn't); this call could otherwise
+ // hang.
+ RunLoop(RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
+
+ // The above RunUntilIdle() guarantees there are no remaining main thread
+ // tasks (the ThreadPool being halted during the last RunUntilIdle() is
+ // key as it prevents a task being posted to it racily with it determining
+ // it had no work remaining). Therefore, we're done if there is no more work
+ // on ThreadPool either (there can be ThreadPool work remaining if
+ // DisallowRunTasks() preempted work and/or the last RunUntilIdle() posted
+ // more ThreadPool tasks).
+ // Note: this last |if| couldn't be turned into a |do {} while();|. A
+ // conditional loop makes it such that |continue;| results in checking the
+ // condition (not unconditionally loop again) which would be incorrect for
+ // the above logic as it'd then be possible for a ThreadPool task to be
+ // running during the DisallowRunTasks() test, causing it to fail, but then
+ // post to the main thread and complete before the loop's condition is
+ // verified which could result in HasIncompleteUndelayedTasksForTesting()
+ // returning false and the loop erroneously exiting with a pending task on
+ // the main thread.
+ if (!task_tracker_->HasIncompleteTaskSourcesForTesting())
+ break;
+ }
+
+ // The above loop always ends with running tasks being disallowed. Re-enable
+ // parallel execution before returning if it was allowed at the beginning of
+ // this call.
+ if (could_run_tasks)
+ task_tracker_->AllowRunTasks();
+}
+
+void TaskEnvironment::FastForwardBy(TimeDelta delta) {
+ DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+ DCHECK(mock_time_domain_);
+ DCHECK_GE(delta, TimeDelta());
+
+ const bool could_run_tasks = task_tracker_ && task_tracker_->AllowRunTasks();
+
+ const TimeTicks fast_forward_until = mock_time_domain_->NowTicks() + delta;
+ do {
+ RunUntilIdle();
+ } while (mock_time_domain_->FastForwardToNextTaskOrCap(fast_forward_until) !=
+ MockTimeDomain::NextTaskSource::kNone);
+
+ if (task_tracker_ && !could_run_tasks)
+ task_tracker_->DisallowRunTasks();
+}
+
+void TaskEnvironment::FastForwardUntilNoTasksRemain() {
+ // TimeTicks::operator+(TimeDelta) uses saturated arithmetic so it's safe to
+ // pass in TimeDelta::Max().
+ FastForwardBy(TimeDelta::Max());
+}
+
+void TaskEnvironment::AdvanceClock(TimeDelta delta) {
+ DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+ DCHECK(mock_time_domain_);
+ DCHECK_GE(delta, TimeDelta());
+ mock_time_domain_->AdvanceClock(delta);
+}
+
+const TickClock* TaskEnvironment::GetMockTickClock() const {
+ DCHECK(mock_time_domain_);
+ return mock_time_domain_.get();
+}
+
+base::TimeTicks TaskEnvironment::NowTicks() const {
+ DCHECK(mock_time_domain_);
+ return mock_time_domain_->Now();
+}
+
+const Clock* TaskEnvironment::GetMockClock() const {
+ DCHECK(mock_clock_);
+ return mock_clock_.get();
+}
+
+size_t TaskEnvironment::GetPendingMainThreadTaskCount() const {
+ DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+
+ // ReclaimMemory sweeps canceled delayed tasks.
+ sequence_manager_->ReclaimMemory();
+ return sequence_manager_->GetPendingTaskCountForTesting();
+}
+
+TimeDelta TaskEnvironment::NextMainThreadPendingTaskDelay() const {
+ DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+
+ // ReclaimMemory sweeps canceled delayed tasks.
+ sequence_manager_->ReclaimMemory();
+ DCHECK(mock_time_domain_);
+ Optional<TimeTicks> run_time = mock_time_domain_->NextScheduledRunTime();
+ if (run_time)
+ return *run_time - mock_time_domain_->Now();
+ return TimeDelta::Max();
+}
+
+bool TaskEnvironment::NextTaskIsDelayed() const {
+ DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+
+ TimeDelta delay = NextMainThreadPendingTaskDelay();
+ return !delay.is_zero() && !delay.is_max();
+}
+
+void TaskEnvironment::DescribePendingMainThreadTasks() const {
+ DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+ LOG(INFO) << sequence_manager_->DescribeAllPendingTasks();
+}
+
+// static
+void TaskEnvironment::AddDestructionObserver(DestructionObserver* observer) {
+ GetDestructionObservers().AddObserver(observer);
+}
+
+// static
+void TaskEnvironment::RemoveDestructionObserver(DestructionObserver* observer) {
+ GetDestructionObservers().RemoveObserver(observer);
+}
+
+TaskEnvironment::TestTaskTracker::TestTaskTracker()
+ : internal::ThreadPoolImpl::TaskTrackerImpl(std::string()),
+ can_run_tasks_cv_(&lock_),
+ task_completed_cv_(&lock_) {
+ // Consider threads blocked on these as idle (avoids instantiating
+ // ScopedBlockingCalls and confusing some //base internals tests).
+ can_run_tasks_cv_.declare_only_used_while_idle();
+ task_completed_cv_.declare_only_used_while_idle();
+}
+
+bool TaskEnvironment::TestTaskTracker::AllowRunTasks() {
+ AutoLock auto_lock(lock_);
+ const bool could_run_tasks = can_run_tasks_;
+ can_run_tasks_ = true;
+ can_run_tasks_cv_.Broadcast();
+ return could_run_tasks;
+}
+
+bool TaskEnvironment::TestTaskTracker::TasksAllowedToRun() const {
+ AutoLock auto_lock(lock_);
+ return can_run_tasks_;
+}
+
+bool TaskEnvironment::TestTaskTracker::DisallowRunTasks() {
+ AutoLock auto_lock(lock_);
+
+ // Can't disallow run task if there are tasks running.
+ if (num_tasks_running_ > 0) {
+ // Attempt to wait a bit so that the caller doesn't busy-loop with the same
+ // set of pending work. A short wait is required to avoid deadlock
+ // scenarios. See DisallowRunTasks()'s declaration for more details.
+ task_completed_cv_.TimedWait(TimeDelta::FromMilliseconds(1));
+ return false;
+ }
+
+ can_run_tasks_ = false;
+ return true;
+}
+
+void TaskEnvironment::TestTaskTracker::RunTask(internal::Task task,
+ internal::TaskSource* sequence,
+ const TaskTraits& traits) {
+ {
+ AutoLock auto_lock(lock_);
+
+ while (!can_run_tasks_)
+ can_run_tasks_cv_.Wait();
+
+ ++num_tasks_running_;
+ }
+
+ {
+ // Using TimeTicksNowIgnoringOverride() because in tests that mock time,
+ // Now() can advance very far very fast, and that's not a problem. This is
+ // watching for tests that have actually long running tasks which cause our
+ // test suites to run slowly.
+ base::TimeTicks before = base::subtle::TimeTicksNowIgnoringOverride();
+ internal::ThreadPoolImpl::TaskTrackerImpl::RunTask(std::move(task),
+ sequence, traits);
+ base::TimeTicks after = base::subtle::TimeTicksNowIgnoringOverride();
+
+ if ((after - before) > TestTimeouts::action_max_timeout()) {
+ ADD_FAILURE() << "TaskEnvironment: RunTask took more than "
+ << TestTimeouts::action_max_timeout().InSeconds()
+ << " seconds. "
+ << "Posted from " << task.posted_from.ToString();
+ }
+ }
+
+ {
+ AutoLock auto_lock(lock_);
+
+ CHECK_GT(num_tasks_running_, 0);
+ CHECK(can_run_tasks_);
+
+ --num_tasks_running_;
+
+ task_completed_cv_.Broadcast();
+ }
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/task_environment.h b/chromium/base/test/task_environment.h
new file mode 100644
index 00000000000..846f10e34ae
--- /dev/null
+++ b/chromium/base/test/task_environment.h
@@ -0,0 +1,445 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TASK_ENVIRONMENT_H_
+#define BASE_TEST_TASK_ENVIRONMENT_H_
+
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task/lazy_thread_pool_task_runner.h"
+#include "base/task/sequence_manager/sequence_manager.h"
+#include "base/test/scoped_run_loop_timeout.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "base/traits_bag.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class Clock;
+class FileDescriptorWatcher;
+class SimpleTaskExecutor;
+class TickClock;
+
+namespace subtle {
+class ScopedTimeClockOverrides;
+}
+
+namespace test {
+
+// This header exposes SingleThreadTaskEnvironment and TaskEnvironment.
+//
+// SingleThreadTaskEnvironment enables the following APIs within its scope:
+// - (Thread|Sequenced)TaskRunnerHandle on the main thread
+// - RunLoop on the main thread
+//
+// TaskEnvironment additionally enables:
+// - posting to base::ThreadPool through base/task/thread_pool.h.
+//
+// Hint: For content::BrowserThreads, use content::BrowserTaskEnvironment.
+//
+// Tests should prefer SingleThreadTaskEnvironment over TaskEnvironment when the
+// former is sufficient.
+//
+// Tasks posted to the (Thread|Sequenced)TaskRunnerHandle run synchronously when
+// RunLoop::Run(UntilIdle) or TaskEnvironment::RunUntilIdle is called on the
+// main thread.
+//
+// The TaskEnvironment requires TestTimeouts::Initialize() to be called in order
+// to run posted tasks, so that it can watch for problematic long-running tasks.
+//
+// The TimeSource trait can be used to request that delayed tasks be under the
+// manual control of RunLoop::Run() and TaskEnvironment::FastForward*() methods.
+//
+// If a TaskEnvironment's ThreadPoolExecutionMode is QUEUED, ThreadPool tasks
+// run when RunUntilIdle() or ~TaskEnvironment is called. If
+// ThreadPoolExecutionMode is ASYNC, they run as they are posted.
+//
+// All TaskEnvironment methods must be called from the main thread.
+//
+// Usage:
+//
+// class MyTestFixture : public testing::Test {
+// public:
+// (...)
+//
+// // protected rather than private visibility will allow controlling the
+// // task environment (e.g. RunUntilIdle(), FastForwardBy(), etc.). from the
+// // test body.
+// protected:
+// // Must generally be the first member to be initialized first and
+// // destroyed last (some members that require single-threaded
+// // initialization and tear down may need to come before -- e.g.
+// // base::test::ScopedFeatureList). Extra traits, like TimeSource, are
+// // best provided inline when declaring the TaskEnvironment, as
+// // such:
+// base::test::TaskEnvironment task_environment_{
+// base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+//
+// // Other members go here (or further below in private section.)
+// };
+class TaskEnvironment {
+ protected:
+ // This enables a two-phase initialization for sub classes such as
+ // content::BrowserTaskEnvironment which need to provide the default task
+ // queue because they instantiate a scheduler on the same thread. Subclasses
+ // using this trait must invoke DeferredInitFromSubclass() before running the
+ // task environment.
+ struct SubclassCreatesDefaultTaskRunner {};
+
+ public:
+ enum class TimeSource {
+ // Delayed tasks and Time/TimeTicks::Now() use the real-time system clock.
+ SYSTEM_TIME,
+
+ // Delayed tasks use a mock clock which only advances when reaching "idle"
+ // during a RunLoop::Run() call on the main thread or a FastForward*() call
+ // to this TaskEnvironment. "idle" is defined as the main thread and thread
+ // pool being out of ready tasks. In that situation : time advances to the
+ // soonest delay between main thread and thread pool delayed tasks,
+ // according to the semantics of the current Run*() or FastForward*() call.
+ //
+ // This also mocks Time/TimeTicks::Now() with the same mock clock.
+ //
+ // Warning some platform APIs are still real-time, e.g.:
+ // * PlatformThread::Sleep
+ // * WaitableEvent::TimedWait
+ // * ConditionVariable::TimedWait
+ // * Delayed tasks on unmanaged base::Thread's and other custom task
+ // runners.
+ MOCK_TIME,
+
+ DEFAULT = SYSTEM_TIME
+ };
+
+ // This type will determine what types of messages will get pumped by the main
+ // thread.
+ // Note: If your test needs to use a custom MessagePump you should
+ // consider using a SingleThreadTaskExecutor instead.
+ enum class MainThreadType {
+ // The main thread doesn't pump system messages.
+ DEFAULT,
+ // The main thread pumps UI messages.
+ UI,
+ // The main thread pumps asynchronous IO messages and supports the
+ // FileDescriptorWatcher API on POSIX.
+ IO,
+ };
+
+ // Note that this is irrelevant (and ignored) under
+ // ThreadingMode::MAIN_THREAD_ONLY
+ enum class ThreadPoolExecutionMode {
+ // Thread pool tasks are queued and only executed when RunUntilIdle(),
+ // FastForwardBy(), or FastForwardUntilNoTasksRemain() are explicitly
+ // called. Note: RunLoop::Run() does *not* unblock the ThreadPool in this
+ // mode (it strictly runs only the main thread).
+ QUEUED,
+ // Thread pool tasks run as they are posted. RunUntilIdle() can still be
+ // used to block until done.
+ // Note that regardless of this trait, delayed tasks are always "queued"
+ // under TimeSource::MOCK_TIME mode.
+ ASYNC,
+ DEFAULT = ASYNC
+ };
+
+ enum class ThreadingMode {
+ // ThreadPool will be initialized, thus adding support for multi-threaded
+ // tests.
+ MULTIPLE_THREADS,
+ // No thread pool will be initialized. Useful for tests that want to run
+ // single threaded. Prefer using SingleThreadTaskEnvironment over this
+ // trait.
+ MAIN_THREAD_ONLY,
+ DEFAULT = MULTIPLE_THREADS
+ };
+
+ // On Windows, sets the COM environment for the ThreadPoolInstance. Ignored
+ // on other platforms.
+ enum class ThreadPoolCOMEnvironment {
+ // Do not initialize COM for the pool's workers.
+ NONE,
+
+ // Place the pool's workers in a COM MTA.
+ COM_MTA,
+
+ // Enable the MTA by default in unit tests to match the browser process's
+ // ThreadPoolInstance configuration.
+ //
+ // This has the adverse side-effect of enabling the MTA in non-browser unit
+ // tests as well but the downside there is not as bad as not having it in
+ // browser unit tests. It just means some COM asserts may pass in unit
+ // tests where they wouldn't in integration tests or prod. That's okay
+ // because unit tests are already generally very loose on allowing I/O,
+ // waits, etc. Such misuse will still be caught in later phases (and COM
+ // usage should already be pretty much inexistent in sandboxed processes).
+ DEFAULT = COM_MTA,
+ };
+
+ // List of traits that are valid inputs for the constructor below.
+ struct ValidTraits {
+ ValidTraits(TimeSource);
+ ValidTraits(MainThreadType);
+ ValidTraits(ThreadPoolExecutionMode);
+ ValidTraits(SubclassCreatesDefaultTaskRunner);
+ ValidTraits(ThreadingMode);
+ ValidTraits(ThreadPoolCOMEnvironment);
+ };
+
+ // Constructor accepts zero or more traits which customize the testing
+ // environment.
+ template <typename... TaskEnvironmentTraits,
+ class CheckArgumentsAreValid = std::enable_if_t<
+ trait_helpers::AreValidTraits<ValidTraits,
+ TaskEnvironmentTraits...>::value>>
+ NOINLINE explicit TaskEnvironment(TaskEnvironmentTraits... traits)
+ : TaskEnvironment(
+ trait_helpers::GetEnum<TimeSource, TimeSource::DEFAULT>(traits...),
+ trait_helpers::GetEnum<MainThreadType, MainThreadType::DEFAULT>(
+ traits...),
+ trait_helpers::GetEnum<ThreadPoolExecutionMode,
+ ThreadPoolExecutionMode::DEFAULT>(traits...),
+ trait_helpers::GetEnum<ThreadingMode, ThreadingMode::DEFAULT>(
+ traits...),
+ trait_helpers::GetEnum<ThreadPoolCOMEnvironment,
+ ThreadPoolCOMEnvironment::DEFAULT>(
+ traits...),
+ trait_helpers::HasTrait<SubclassCreatesDefaultTaskRunner,
+ TaskEnvironmentTraits...>(),
+ trait_helpers::NotATraitTag()) {}
+
+ // Waits until no undelayed ThreadPool tasks remain. Then, unregisters the
+ // ThreadPoolInstance and the (Thread|Sequenced)TaskRunnerHandle.
+ virtual ~TaskEnvironment();
+
+ // Returns a TaskRunner that schedules tasks on the main thread.
+ scoped_refptr<base::SingleThreadTaskRunner> GetMainThreadTaskRunner();
+
+ // Returns whether the main thread's TaskRunner has pending tasks. This will
+ // always return true if called right after RunUntilIdle.
+ bool MainThreadIsIdle() const;
+
+ // Runs tasks until both the (Thread|Sequenced)TaskRunnerHandle and the
+ // ThreadPool's non-delayed queues are empty.
+ // While RunUntilIdle() is quite practical and sometimes even necessary -- for
+ // example, to flush all tasks bound to Unretained() state before destroying
+ // test members -- it should be used with caution per the following warnings:
+ //
+ // WARNING #1: This may run long (flakily timeout) and even never return! Do
+ // not use this when repeating tasks such as animated web pages
+ // are present.
+ // WARNING #2: This may return too early! For example, if used to run until an
+ // incoming event has occurred but that event depends on a task in
+ // a different queue -- e.g. a standalone base::Thread or a system
+ // event.
+ //
+ // As such, prefer RunLoop::Run() with an explicit RunLoop::QuitClosure() when
+ // possible.
+ void RunUntilIdle();
+
+ // Only valid for instances using TimeSource::MOCK_TIME. Fast-forwards
+ // virtual time by |delta|, causing all tasks on the main thread and thread
+ // pool with a remaining delay less than or equal to |delta| to be executed in
+ // their natural order before this returns. |delta| must be non-negative. Upon
+ // returning from this method, NowTicks() will be >= the initial |NowTicks() +
+ // delta|. It is guaranteed to be == iff tasks executed in this
+ // FastForwardBy() didn't result in nested calls to time-advancing-methods.
+ void FastForwardBy(TimeDelta delta);
+
+ // Only valid for instances using TimeSource::MOCK_TIME.
+ // Short for FastForwardBy(TimeDelta::Max()).
+ //
+ // WARNING: This has the same caveat as RunUntilIdle() and is even more likely
+ // to spin forever (any RepeatingTimer will cause this).
+ void FastForwardUntilNoTasksRemain();
+
+ // Only valid for instances using TimeSource::MOCK_TIME. Advances virtual time
+ // by |delta|. Unlike FastForwardBy, this does not run tasks. Prefer
+ // FastForwardBy() when possible but this can be useful when testing blocked
+ // pending tasks where being idle (required to fast-forward) is not possible.
+ //
+ // Delayed tasks that are ripe as a result of this will be scheduled.
+ // RunUntilIdle() can be used after this call to ensure those tasks have run.
+ // Note: AdvanceClock(delta) + RunUntilIdle() is slightly different from
+ // FastForwardBy(delta) in that time passes instantly before running any task
+ // (whereas FastForwardBy() will advance the clock in the smallest increments
+ // possible at a time). Hence FastForwardBy() is more realistic but
+ // AdvanceClock() can be useful when testing edge case scenarios that
+ // specifically handle more time than expected to have passed.
+ void AdvanceClock(TimeDelta delta);
+
+ // Only valid for instances using TimeSource::MOCK_TIME. Returns a
+ // TickClock whose time is updated by FastForward(By|UntilNoTasksRemain).
+ const TickClock* GetMockTickClock() const;
+ std::unique_ptr<TickClock> DeprecatedGetMockTickClock();
+
+ // Only valid for instances using TimeSource::MOCK_TIME. Returns a
+ // Clock whose time is updated by FastForward(By|UntilNoTasksRemain). The
+ // initial value is implementation defined and should be queried by tests that
+ // depend on it.
+ // TickClock should be used instead of Clock to measure elapsed time in a
+ // process. See time.h.
+ const Clock* GetMockClock() const;
+
+ // Only valid for instances using TimeSource::MOCK_TIME. Returns the current
+ // virtual tick time (based on a realistic Now(), sampled when this
+ // TaskEnvironment was created, and manually advanced from that point on).
+ // This is always equivalent to base::TimeTicks::Now() under
+ // TimeSource::MOCK_TIME.
+ base::TimeTicks NowTicks() const;
+
+ // Only valid for instances using TimeSource::MOCK_TIME. Returns the
+ // number of pending tasks (delayed and non-delayed) of the main thread's
+ // TaskRunner. When debugging, you can use DescribePendingMainThreadTasks() to
+ // see what those are.
+ size_t GetPendingMainThreadTaskCount() const;
+
+ // Only valid for instances using TimeSource::MOCK_TIME.
+ // Returns the delay until the next pending task of the main thread's
+ // TaskRunner if there is one, otherwise it returns TimeDelta::Max().
+ TimeDelta NextMainThreadPendingTaskDelay() const;
+
+ // Only valid for instances using TimeSource::MOCK_TIME.
+ // Returns true iff the next task is delayed. Returns false if the next task
+ // is immediate or if there is no next task.
+ bool NextTaskIsDelayed() const;
+
+ // For debugging purposes: Dumps information about pending tasks on the main
+ // thread.
+ void DescribePendingMainThreadTasks() const;
+
+ class DestructionObserver : public CheckedObserver {
+ public:
+ DestructionObserver() = default;
+ ~DestructionObserver() override = default;
+
+ DestructionObserver(const DestructionObserver&) = delete;
+ DestructionObserver& operator=(const DestructionObserver&) = delete;
+
+ virtual void WillDestroyCurrentTaskEnvironment() = 0;
+ };
+
+ // Adds/removes a DestructionObserver to any TaskEnvironment. Observers are
+ // notified when any TaskEnvironment goes out of scope (other than with a move
+ // operation). Must be called on the main thread.
+ static void AddDestructionObserver(DestructionObserver* observer);
+ static void RemoveDestructionObserver(DestructionObserver* observer);
+
+ // The number of foreground workers in the ThreadPool managed by a
+ // TaskEnvironment instance. This can be used to determine the maximum
+ // parallelism in tests that require each parallel task it spawns to be
+ // running at once. Having multiple threads prevents deadlocks should some
+ // blocking APIs not use ScopedBlockingCall. It also allows enough concurrency
+ // to allow TSAN to spot data races.
+ static constexpr int kNumForegroundThreadPoolThreads = 4;
+
+ protected:
+ explicit TaskEnvironment(TaskEnvironment&& other);
+
+ constexpr MainThreadType main_thread_type() const {
+ return main_thread_type_;
+ }
+
+ constexpr ThreadPoolExecutionMode thread_pool_execution_mode() const {
+ return thread_pool_execution_mode_;
+ }
+
+ // Returns the TimeDomain driving this TaskEnvironment.
+ sequence_manager::TimeDomain* GetTimeDomain() const;
+
+ sequence_manager::SequenceManager* sequence_manager() const;
+
+ void DeferredInitFromSubclass(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+ // Derived classes may need to control when the sequence manager goes away.
+ void NotifyDestructionObserversAndReleaseSequenceManager();
+
+ private:
+ class TestTaskTracker;
+ class MockTimeDomain;
+
+ void InitializeThreadPool();
+ void DestroyThreadPool();
+
+ void CompleteInitialization();
+
+ // The template constructor has to be in the header but it delegates to this
+ // constructor to initialize all other members out-of-line.
+ TaskEnvironment(TimeSource time_source,
+ MainThreadType main_thread_type,
+ ThreadPoolExecutionMode thread_pool_execution_mode,
+ ThreadingMode threading_mode,
+ ThreadPoolCOMEnvironment thread_pool_com_environment,
+ bool subclass_creates_default_taskrunner,
+ trait_helpers::NotATraitTag tag);
+
+ const MainThreadType main_thread_type_;
+ const ThreadPoolExecutionMode thread_pool_execution_mode_;
+ const ThreadingMode threading_mode_;
+ const ThreadPoolCOMEnvironment thread_pool_com_environment_;
+ const bool subclass_creates_default_taskrunner_;
+
+ std::unique_ptr<sequence_manager::SequenceManager> sequence_manager_;
+
+ // Manages the clock under TimeSource::MOCK_TIME modes. Null in
+ // TimeSource::SYSTEM_TIME mode.
+ std::unique_ptr<MockTimeDomain> mock_time_domain_;
+
+ // Overrides Time/TimeTicks::Now() under TimeSource::MOCK_TIME_AND_NOW mode.
+ // Null in other modes.
+ std::unique_ptr<subtle::ScopedTimeClockOverrides> time_overrides_;
+
+ scoped_refptr<sequence_manager::TaskQueue> task_queue_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ // Only set for instances using TimeSource::MOCK_TIME.
+ std::unique_ptr<Clock> mock_clock_;
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+ // Enables the FileDescriptorWatcher API iff running a MainThreadType::IO.
+ std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher_;
+#endif
+
+ // Owned by the ThreadPoolInstance.
+ TestTaskTracker* task_tracker_ = nullptr;
+
+ // Ensures destruction of lazy TaskRunners when this is destroyed.
+ std::unique_ptr<internal::ScopedLazyTaskRunnerListForTesting>
+ scoped_lazy_task_runner_list_for_testing_;
+
+ // Sets RunLoop::Run() to LOG(FATAL) if not Quit() in a timely manner.
+ std::unique_ptr<ScopedRunLoopTimeout> run_loop_timeout_;
+
+ std::unique_ptr<bool> owns_instance_ = std::make_unique<bool>(true);
+
+ // To support base::CurrentThread().
+ std::unique_ptr<SimpleTaskExecutor> simple_task_executor_;
+
+ // Used to verify thread-affinity of operations that must occur on the main
+ // thread. This is the case for anything that modifies or drives the
+ // |sequence_manager_|.
+ THREAD_CHECKER(main_thread_checker_);
+
+ DISALLOW_COPY_AND_ASSIGN(TaskEnvironment);
+};
+
+// SingleThreadTaskEnvironment takes the same traits as TaskEnvironment and is
+// used the exact same way. It's a short-form for
+// TaskEnvironment{TaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY, ...};
+class SingleThreadTaskEnvironment : public TaskEnvironment {
+ public:
+ template <class... ArgTypes>
+ SingleThreadTaskEnvironment(ArgTypes... args)
+ : TaskEnvironment(ThreadingMode::MAIN_THREAD_ONLY, args...) {}
+};
+
+} // namespace test
+} // namespace base
+
+#endif // BASE_TEST_TASK_ENVIRONMENT_H_
diff --git a/chromium/base/test/task_environment_unittest.cc b/chromium/base/test/task_environment_unittest.cc
new file mode 100644
index 00000000000..5d20d60f2c1
--- /dev/null
+++ b/chromium/base/test/task_environment_unittest.cc
@@ -0,0 +1,1274 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/task_environment.h"
+
+#include <atomic>
+#include <memory>
+
+#include "base/atomicops.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/cancelable_callback.h"
+#include "base/debug/debugger.h"
+#include "base/message_loop/message_loop_current.h"
+#include "base/run_loop.h"
+#include "base/synchronization/atomic_flag.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task/sequence_manager/time_domain.h"
+#include "base/task/thread_pool.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/gtest_util.h"
+#include "base/test/mock_callback.h"
+#include "base/test/mock_log.h"
+#include "base/test/scoped_run_loop_timeout.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/sequence_local_storage_slot.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/clock.h"
+#include "base/time/default_clock.h"
+#include "base/time/tick_clock.h"
+#include "base/win/com_init_util.h"
+#include "build/build_config.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest-spi.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_POSIX)
+#include <unistd.h>
+
+#include "base/files/file_descriptor_watcher_posix.h"
+#endif // defined(OS_POSIX)
+
+#if defined(OS_WIN)
+#include "base/win/scoped_com_initializer.h"
+#endif
+
+namespace base {
+namespace test {
+
+namespace {
+
+using ::testing::_;
+using ::testing::HasSubstr;
+using ::testing::IsNull;
+using ::testing::Not;
+using ::testing::Return;
+
+class TaskEnvironmentTest : public testing::Test {};
+
+void VerifyRunUntilIdleDidNotReturnAndSetFlag(
+ AtomicFlag* run_until_idle_returned,
+ AtomicFlag* task_ran) {
+ EXPECT_FALSE(run_until_idle_returned->IsSet());
+ task_ran->Set();
+}
+
+void RunUntilIdleTest(
+ TaskEnvironment::ThreadPoolExecutionMode thread_pool_execution_mode) {
+ AtomicFlag run_until_idle_returned;
+ TaskEnvironment task_environment(thread_pool_execution_mode);
+
+ AtomicFlag first_main_thread_task_ran;
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, BindOnce(&VerifyRunUntilIdleDidNotReturnAndSetFlag,
+ Unretained(&run_until_idle_returned),
+ Unretained(&first_main_thread_task_ran)));
+
+ AtomicFlag first_thread_pool_task_ran;
+ ThreadPool::PostTask(FROM_HERE,
+ BindOnce(&VerifyRunUntilIdleDidNotReturnAndSetFlag,
+ Unretained(&run_until_idle_returned),
+ Unretained(&first_thread_pool_task_ran)));
+
+ AtomicFlag second_thread_pool_task_ran;
+ AtomicFlag second_main_thread_task_ran;
+ ThreadPool::PostTaskAndReply(
+ FROM_HERE,
+ BindOnce(&VerifyRunUntilIdleDidNotReturnAndSetFlag,
+ Unretained(&run_until_idle_returned),
+ Unretained(&second_thread_pool_task_ran)),
+ BindOnce(&VerifyRunUntilIdleDidNotReturnAndSetFlag,
+ Unretained(&run_until_idle_returned),
+ Unretained(&second_main_thread_task_ran)));
+
+ task_environment.RunUntilIdle();
+ run_until_idle_returned.Set();
+
+ EXPECT_TRUE(first_main_thread_task_ran.IsSet());
+ EXPECT_TRUE(first_thread_pool_task_ran.IsSet());
+ EXPECT_TRUE(second_thread_pool_task_ran.IsSet());
+ EXPECT_TRUE(second_main_thread_task_ran.IsSet());
+}
+
+} // namespace
+
+TEST_F(TaskEnvironmentTest, QueuedRunUntilIdle) {
+ RunUntilIdleTest(TaskEnvironment::ThreadPoolExecutionMode::QUEUED);
+}
+
+TEST_F(TaskEnvironmentTest, AsyncRunUntilIdle) {
+ RunUntilIdleTest(TaskEnvironment::ThreadPoolExecutionMode::ASYNC);
+}
+
+// Verify that tasks posted to an ThreadPoolExecutionMode::QUEUED
+// TaskEnvironment do not run outside of RunUntilIdle().
+TEST_F(TaskEnvironmentTest, QueuedTasksDoNotRunOutsideOfRunUntilIdle) {
+ TaskEnvironment task_environment(
+ TaskEnvironment::ThreadPoolExecutionMode::QUEUED);
+
+ AtomicFlag run_until_idle_called;
+ ThreadPool::PostTask(FROM_HERE,
+ BindOnce(
+ [](AtomicFlag* run_until_idle_called) {
+ EXPECT_TRUE(run_until_idle_called->IsSet());
+ },
+ Unretained(&run_until_idle_called)));
+ PlatformThread::Sleep(TestTimeouts::tiny_timeout());
+ run_until_idle_called.Set();
+ task_environment.RunUntilIdle();
+
+ AtomicFlag other_run_until_idle_called;
+ ThreadPool::PostTask(FROM_HERE,
+ BindOnce(
+ [](AtomicFlag* other_run_until_idle_called) {
+ EXPECT_TRUE(other_run_until_idle_called->IsSet());
+ },
+ Unretained(&other_run_until_idle_called)));
+ PlatformThread::Sleep(TestTimeouts::tiny_timeout());
+ other_run_until_idle_called.Set();
+ task_environment.RunUntilIdle();
+}
+
+// Verify that a task posted to an ThreadPoolExecutionMode::ASYNC
+// TaskEnvironment can run without a call to RunUntilIdle().
+TEST_F(TaskEnvironmentTest, AsyncTasksRunAsTheyArePosted) {
+ TaskEnvironment task_environment(
+ TaskEnvironment::ThreadPoolExecutionMode::ASYNC);
+
+ WaitableEvent task_ran;
+ ThreadPool::PostTask(FROM_HERE,
+ BindOnce(&WaitableEvent::Signal, Unretained(&task_ran)));
+ task_ran.Wait();
+}
+
+// Verify that a task posted to an ThreadPoolExecutionMode::ASYNC
+// TaskEnvironment after a call to RunUntilIdle() can run without another
+// call to RunUntilIdle().
+TEST_F(TaskEnvironmentTest, AsyncTasksRunAsTheyArePostedAfterRunUntilIdle) {
+ TaskEnvironment task_environment(
+ TaskEnvironment::ThreadPoolExecutionMode::ASYNC);
+
+ task_environment.RunUntilIdle();
+
+ WaitableEvent task_ran;
+ ThreadPool::PostTask(FROM_HERE,
+ BindOnce(&WaitableEvent::Signal, Unretained(&task_ran)));
+ task_ran.Wait();
+}
+
+void DelayedTasksTest(TaskEnvironment::TimeSource time_source) {
+ // Use a QUEUED execution-mode environment, so that no tasks are actually
+ // executed until RunUntilIdle()/FastForwardBy() are invoked.
+ TaskEnvironment task_environment(
+ time_source, TaskEnvironment::ThreadPoolExecutionMode::QUEUED);
+
+ subtle::Atomic32 counter = 0;
+
+ constexpr base::TimeDelta kShortTaskDelay = TimeDelta::FromDays(1);
+ // Should run only in MOCK_TIME environment when time is fast-forwarded.
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ BindOnce(
+ [](subtle::Atomic32* counter) {
+ subtle::NoBarrier_AtomicIncrement(counter, 4);
+ },
+ Unretained(&counter)),
+ kShortTaskDelay);
+ ThreadPool::PostDelayedTask(FROM_HERE,
+ BindOnce(
+ [](subtle::Atomic32* counter) {
+ subtle::NoBarrier_AtomicIncrement(counter,
+ 128);
+ },
+ Unretained(&counter)),
+ kShortTaskDelay);
+
+ constexpr base::TimeDelta kLongTaskDelay = TimeDelta::FromDays(7);
+ // Same as first task, longer delays to exercise
+ // FastForwardUntilNoTasksRemain().
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ BindOnce(
+ [](subtle::Atomic32* counter) {
+ subtle::NoBarrier_AtomicIncrement(counter, 8);
+ },
+ Unretained(&counter)),
+ TimeDelta::FromDays(5));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ BindOnce(
+ [](subtle::Atomic32* counter) {
+ subtle::NoBarrier_AtomicIncrement(counter, 16);
+ },
+ Unretained(&counter)),
+ kLongTaskDelay);
+ ThreadPool::PostDelayedTask(FROM_HERE,
+ BindOnce(
+ [](subtle::Atomic32* counter) {
+ subtle::NoBarrier_AtomicIncrement(counter,
+ 256);
+ },
+ Unretained(&counter)),
+ kLongTaskDelay * 2);
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ BindOnce(
+ [](subtle::Atomic32* counter) {
+ subtle::NoBarrier_AtomicIncrement(counter, 512);
+ },
+ Unretained(&counter)),
+ kLongTaskDelay * 3);
+ ThreadPool::PostDelayedTask(FROM_HERE,
+ BindOnce(
+ [](subtle::Atomic32* counter) {
+ subtle::NoBarrier_AtomicIncrement(counter,
+ 1024);
+ },
+ Unretained(&counter)),
+ kLongTaskDelay * 4);
+
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, BindOnce(
+ [](subtle::Atomic32* counter) {
+ subtle::NoBarrier_AtomicIncrement(counter, 1);
+ },
+ Unretained(&counter)));
+ ThreadPool::PostTask(FROM_HERE, BindOnce(
+ [](subtle::Atomic32* counter) {
+ subtle::NoBarrier_AtomicIncrement(
+ counter, 2);
+ },
+ Unretained(&counter)));
+
+ // This expectation will fail flakily if the preceding PostTask() is executed
+ // asynchronously, indicating a problem with the QUEUED execution mode.
+ int expected_value = 0;
+ EXPECT_EQ(expected_value, counter);
+
+ // RunUntilIdle() should process non-delayed tasks only in all queues.
+ task_environment.RunUntilIdle();
+ expected_value += 1;
+ expected_value += 2;
+ EXPECT_EQ(expected_value, counter);
+
+ if (time_source == TaskEnvironment::TimeSource::MOCK_TIME) {
+ const TimeTicks start_time = task_environment.NowTicks();
+
+ // Delay inferior to the delay of the first posted task.
+ constexpr base::TimeDelta kInferiorTaskDelay = TimeDelta::FromSeconds(1);
+ static_assert(kInferiorTaskDelay < kShortTaskDelay,
+ "|kInferiorTaskDelay| should be "
+ "set to a value inferior to the first posted task's delay.");
+ task_environment.FastForwardBy(kInferiorTaskDelay);
+ EXPECT_EQ(expected_value, counter);
+
+ task_environment.FastForwardBy(kShortTaskDelay - kInferiorTaskDelay);
+ expected_value += 4;
+ expected_value += 128;
+ EXPECT_EQ(expected_value, counter);
+
+ task_environment.FastForwardUntilNoTasksRemain();
+ expected_value += 8;
+ expected_value += 16;
+ expected_value += 256;
+ expected_value += 512;
+ expected_value += 1024;
+ EXPECT_EQ(expected_value, counter);
+
+ EXPECT_EQ(task_environment.NowTicks() - start_time, kLongTaskDelay * 4);
+ }
+}
+
+TEST_F(TaskEnvironmentTest, DelayedTasksUnderSystemTime) {
+ DelayedTasksTest(TaskEnvironment::TimeSource::SYSTEM_TIME);
+}
+
+TEST_F(TaskEnvironmentTest, DelayedTasksUnderMockTime) {
+ DelayedTasksTest(TaskEnvironment::TimeSource::MOCK_TIME);
+}
+
+// Regression test for https://crbug.com/824770.
+void SupportsSequenceLocalStorageOnMainThreadTest(
+ TaskEnvironment::TimeSource time_source) {
+ TaskEnvironment task_environment(
+ time_source, TaskEnvironment::ThreadPoolExecutionMode::ASYNC);
+
+ SequenceLocalStorageSlot<int> sls_slot;
+ sls_slot.emplace(5);
+ EXPECT_EQ(5, *sls_slot);
+}
+
+TEST_F(TaskEnvironmentTest, SupportsSequenceLocalStorageOnMainThread) {
+ SupportsSequenceLocalStorageOnMainThreadTest(
+ TaskEnvironment::TimeSource::SYSTEM_TIME);
+}
+
+TEST_F(TaskEnvironmentTest,
+ SupportsSequenceLocalStorageOnMainThreadWithMockTime) {
+ SupportsSequenceLocalStorageOnMainThreadTest(
+ TaskEnvironment::TimeSource::MOCK_TIME);
+}
+
+// Verify that the right MessagePump is instantiated under each MainThreadType.
+// This avoids having to run all other TaskEnvironmentTests in every
+// MainThreadType which is redundant (message loop and message pump tests
+// otherwise cover the advanced functionality provided by UI/IO pumps).
+TEST_F(TaskEnvironmentTest, MainThreadType) {
+ // Uses MessageLoopCurrent as a convenience accessor but could be replaced by
+ // different accessors when we get rid of MessageLoopCurrent.
+ EXPECT_FALSE(MessageLoopCurrent::IsSet());
+ EXPECT_FALSE(MessageLoopCurrentForUI::IsSet());
+ EXPECT_FALSE(MessageLoopCurrentForIO::IsSet());
+ {
+ TaskEnvironment task_environment;
+ EXPECT_TRUE(MessageLoopCurrent::IsSet());
+ EXPECT_FALSE(MessageLoopCurrentForUI::IsSet());
+ EXPECT_FALSE(MessageLoopCurrentForIO::IsSet());
+ }
+ {
+ TaskEnvironment task_environment(TaskEnvironment::MainThreadType::UI);
+ EXPECT_TRUE(MessageLoopCurrent::IsSet());
+ EXPECT_TRUE(MessageLoopCurrentForUI::IsSet());
+ EXPECT_FALSE(MessageLoopCurrentForIO::IsSet());
+ }
+ {
+ TaskEnvironment task_environment(TaskEnvironment::MainThreadType::IO);
+ EXPECT_TRUE(MessageLoopCurrent::IsSet());
+ EXPECT_FALSE(MessageLoopCurrentForUI::IsSet());
+ EXPECT_TRUE(MessageLoopCurrentForIO::IsSet());
+ }
+ EXPECT_FALSE(MessageLoopCurrent::IsSet());
+ EXPECT_FALSE(MessageLoopCurrentForUI::IsSet());
+ EXPECT_FALSE(MessageLoopCurrentForIO::IsSet());
+}
+
+#if defined(OS_POSIX)
+TEST_F(TaskEnvironmentTest, SupportsFileDescriptorWatcherOnIOMainThread) {
+ TaskEnvironment task_environment(TaskEnvironment::MainThreadType::IO);
+
+ int pipe_fds_[2];
+ ASSERT_EQ(0, pipe(pipe_fds_));
+
+ RunLoop run_loop;
+
+ // The write end of a newly created pipe is immediately writable.
+ auto controller = FileDescriptorWatcher::WatchWritable(
+ pipe_fds_[1], run_loop.QuitClosure());
+
+ // This will hang if the notification doesn't occur as expected.
+ run_loop.Run();
+}
+
+TEST_F(TaskEnvironmentTest,
+ SupportsFileDescriptorWatcherOnIOMockTimeMainThread) {
+ TaskEnvironment task_environment(TaskEnvironment::MainThreadType::IO,
+ TaskEnvironment::TimeSource::MOCK_TIME);
+
+ int pipe_fds_[2];
+ ASSERT_EQ(0, pipe(pipe_fds_));
+
+ RunLoop run_loop;
+
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, BindLambdaForTesting([&]() {
+ int64_t x = 1;
+ auto ret = write(pipe_fds_[1], &x, sizeof(x));
+ ASSERT_EQ(static_cast<size_t>(ret), sizeof(x));
+ }),
+ TimeDelta::FromHours(1));
+
+ auto controller = FileDescriptorWatcher::WatchReadable(
+ pipe_fds_[0], run_loop.QuitClosure());
+
+ // This will hang if the notification doesn't occur as expected (Run() should
+ // fast-forward-time when idle).
+ run_loop.Run();
+}
+#endif // defined(OS_POSIX)
+
+// Verify that the TickClock returned by
+// |TaskEnvironment::GetMockTickClock| gets updated when the
+// FastForward(By|UntilNoTasksRemain) functions are called.
+TEST_F(TaskEnvironmentTest, FastForwardAdvancesTickClock) {
+ // Use a QUEUED execution-mode environment, so that no tasks are actually
+ // executed until RunUntilIdle()/FastForwardBy() are invoked.
+ TaskEnvironment task_environment(
+ TaskEnvironment::TimeSource::MOCK_TIME,
+ TaskEnvironment::ThreadPoolExecutionMode::QUEUED);
+
+ constexpr base::TimeDelta kShortTaskDelay = TimeDelta::FromDays(1);
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, base::DoNothing(),
+ kShortTaskDelay);
+
+ constexpr base::TimeDelta kLongTaskDelay = TimeDelta::FromDays(7);
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, base::DoNothing(),
+ kLongTaskDelay);
+
+ const base::TickClock* tick_clock = task_environment.GetMockTickClock();
+ base::TimeTicks tick_clock_ref = tick_clock->NowTicks();
+
+ // Make sure that |FastForwardBy| advances the clock.
+ task_environment.FastForwardBy(kShortTaskDelay);
+ EXPECT_EQ(kShortTaskDelay, tick_clock->NowTicks() - tick_clock_ref);
+
+ // Make sure that |FastForwardUntilNoTasksRemain| advances the clock.
+ task_environment.FastForwardUntilNoTasksRemain();
+ EXPECT_EQ(kLongTaskDelay, tick_clock->NowTicks() - tick_clock_ref);
+
+ // Fast-forwarding to a time at which there's no tasks should also advance the
+ // clock.
+ task_environment.FastForwardBy(kLongTaskDelay);
+ EXPECT_EQ(kLongTaskDelay * 2, tick_clock->NowTicks() - tick_clock_ref);
+}
+
+TEST_F(TaskEnvironmentTest, FastForwardAdvancesMockClock) {
+ constexpr base::TimeDelta kDelay = TimeDelta::FromSeconds(42);
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ const Clock* clock = task_environment.GetMockClock();
+ const Time start_time = clock->Now();
+ task_environment.FastForwardBy(kDelay);
+
+ EXPECT_EQ(start_time + kDelay, clock->Now());
+}
+
+TEST_F(TaskEnvironmentTest, FastForwardAdvancesTime) {
+ constexpr base::TimeDelta kDelay = TimeDelta::FromSeconds(42);
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ const Time start_time = base::Time::Now();
+ task_environment.FastForwardBy(kDelay);
+ EXPECT_EQ(start_time + kDelay, base::Time::Now());
+}
+
+TEST_F(TaskEnvironmentTest, FastForwardAdvancesTimeTicks) {
+ constexpr base::TimeDelta kDelay = TimeDelta::FromSeconds(42);
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ const TimeTicks start_time = base::TimeTicks::Now();
+ task_environment.FastForwardBy(kDelay);
+ EXPECT_EQ(start_time + kDelay, base::TimeTicks::Now());
+}
+
+TEST_F(TaskEnvironmentTest, AdvanceClockAdvancesTickClock) {
+ constexpr base::TimeDelta kDelay = TimeDelta::FromSeconds(42);
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ const base::TickClock* tick_clock = task_environment.GetMockTickClock();
+ const base::TimeTicks start_time = tick_clock->NowTicks();
+ task_environment.AdvanceClock(kDelay);
+
+ EXPECT_EQ(start_time + kDelay, tick_clock->NowTicks());
+}
+
+TEST_F(TaskEnvironmentTest, AdvanceClockAdvancesMockClock) {
+ constexpr base::TimeDelta kDelay = TimeDelta::FromSeconds(42);
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ const Clock* clock = task_environment.GetMockClock();
+ const Time start_time = clock->Now();
+ task_environment.AdvanceClock(kDelay);
+
+ EXPECT_EQ(start_time + kDelay, clock->Now());
+}
+
+TEST_F(TaskEnvironmentTest, AdvanceClockAdvancesTime) {
+ constexpr base::TimeDelta kDelay = TimeDelta::FromSeconds(42);
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ const Time start_time = base::Time::Now();
+ task_environment.AdvanceClock(kDelay);
+ EXPECT_EQ(start_time + kDelay, base::Time::Now());
+}
+
+TEST_F(TaskEnvironmentTest, AdvanceClockAdvancesTimeTicks) {
+ constexpr base::TimeDelta kDelay = TimeDelta::FromSeconds(42);
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ const TimeTicks start_time = base::TimeTicks::Now();
+ task_environment.AdvanceClock(kDelay);
+ EXPECT_EQ(start_time + kDelay, base::TimeTicks::Now());
+}
+
+TEST_F(TaskEnvironmentTest, AdvanceClockDoesNotRunTasks) {
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ constexpr base::TimeDelta kTaskDelay = TimeDelta::FromDays(1);
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, base::DoNothing(),
+ kTaskDelay);
+
+ EXPECT_EQ(1U, task_environment.GetPendingMainThreadTaskCount());
+ EXPECT_TRUE(task_environment.NextTaskIsDelayed());
+
+ task_environment.AdvanceClock(kTaskDelay);
+
+ // The task is still pending, but is now runnable.
+ EXPECT_EQ(1U, task_environment.GetPendingMainThreadTaskCount());
+ EXPECT_FALSE(task_environment.NextTaskIsDelayed());
+}
+
+TEST_F(TaskEnvironmentTest, AdvanceClockSchedulesRipeDelayedTasks) {
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ bool ran = false;
+
+ constexpr base::TimeDelta kTaskDelay = TimeDelta::FromDays(1);
+ ThreadPool::PostDelayedTask(
+ FROM_HERE, base::BindLambdaForTesting([&]() { ran = true; }), kTaskDelay);
+
+ task_environment.AdvanceClock(kTaskDelay);
+ EXPECT_FALSE(ran);
+ task_environment.RunUntilIdle();
+ EXPECT_TRUE(ran);
+}
+
+// Verify that FastForwardBy() runs existing immediate tasks before advancing,
+// then advances to the next delayed task, runs it, then advances the remainder
+// of time when out of tasks.
+TEST_F(TaskEnvironmentTest, FastForwardOnlyAdvancesWhenIdle) {
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ const TimeTicks start_time = base::TimeTicks::Now();
+
+ constexpr base::TimeDelta kDelay = TimeDelta::FromSeconds(42);
+ constexpr base::TimeDelta kFastForwardUntil = TimeDelta::FromSeconds(100);
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, BindLambdaForTesting(
+ [&]() { EXPECT_EQ(start_time, base::TimeTicks::Now()); }));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, BindLambdaForTesting([&]() {
+ EXPECT_EQ(start_time + kDelay, base::TimeTicks::Now());
+ }),
+ kDelay);
+ task_environment.FastForwardBy(kFastForwardUntil);
+ EXPECT_EQ(start_time + kFastForwardUntil, base::TimeTicks::Now());
+}
+
+// FastForwardBy(0) should be equivalent of RunUntilIdle().
+TEST_F(TaskEnvironmentTest, FastForwardZero) {
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ std::atomic_int run_count{0};
+
+ for (int i = 0; i < 1000; ++i) {
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, BindLambdaForTesting([&]() {
+ run_count.fetch_add(1, std::memory_order_relaxed);
+ }));
+ ThreadPool::PostTask(FROM_HERE, BindLambdaForTesting([&]() {
+ run_count.fetch_add(1, std::memory_order_relaxed);
+ }));
+ }
+
+ task_environment.FastForwardBy(base::TimeDelta());
+
+ EXPECT_EQ(2000, run_count.load(std::memory_order_relaxed));
+}
+
+TEST_F(TaskEnvironmentTest, NestedFastForwardBy) {
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ constexpr TimeDelta kDelayPerTask = TimeDelta::FromMilliseconds(1);
+ const TimeTicks start_time = task_environment.NowTicks();
+
+ int max_nesting_level = 0;
+
+ RepeatingClosure post_fast_forwarding_task;
+ post_fast_forwarding_task = BindLambdaForTesting([&]() {
+ if (max_nesting_level < 5) {
+ ++max_nesting_level;
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, post_fast_forwarding_task, kDelayPerTask);
+ task_environment.FastForwardBy(kDelayPerTask);
+ }
+ });
+ post_fast_forwarding_task.Run();
+
+ EXPECT_EQ(max_nesting_level, 5);
+ EXPECT_EQ(task_environment.NowTicks(), start_time + kDelayPerTask * 5);
+}
+
+TEST_F(TaskEnvironmentTest, NestedRunInFastForwardBy) {
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ constexpr TimeDelta kDelayPerTask = TimeDelta::FromMilliseconds(1);
+ const TimeTicks start_time = task_environment.NowTicks();
+
+ std::vector<RunLoop*> run_loops;
+
+ RepeatingClosure post_and_runloop_task;
+ post_and_runloop_task = BindLambdaForTesting([&]() {
+ // Run 4 nested run loops on top of the initial FastForwardBy().
+ if (run_loops.size() < 4U) {
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, post_and_runloop_task, kDelayPerTask);
+
+ RunLoop run_loop(RunLoop::Type::kNestableTasksAllowed);
+ run_loops.push_back(&run_loop);
+ run_loop.Run();
+ } else {
+ for (RunLoop* run_loop : run_loops) {
+ run_loop->Quit();
+ }
+ }
+ });
+
+ // Initial task is FastForwardBy().
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, post_and_runloop_task, kDelayPerTask);
+ task_environment.FastForwardBy(kDelayPerTask);
+
+ EXPECT_EQ(run_loops.size(), 4U);
+ EXPECT_EQ(task_environment.NowTicks(), start_time + kDelayPerTask * 5);
+}
+
+TEST_F(TaskEnvironmentTest,
+ CrossThreadImmediateTaskPostingDoesntAffectMockTime) {
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ int count = 0;
+
+ // Post tasks delayd between 0 and 999 seconds.
+ for (int i = 0; i < 1000; ++i) {
+ const TimeDelta delay = TimeDelta::FromSeconds(i);
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ BindOnce(
+ [](TimeTicks expected_run_time, int* count) {
+ EXPECT_EQ(expected_run_time, TimeTicks::Now());
+ ++*count;
+ },
+ TimeTicks::Now() + delay, &count),
+ delay);
+ }
+
+ // Having a bunch of tasks running in parallel and replying to the main thread
+ // shouldn't affect the rest of this test. Wait for the first task to run
+ // before proceeding with the test to increase the likelihood of exercising
+ // races.
+ base::WaitableEvent first_reply_is_incoming;
+ for (int i = 0; i < 1000; ++i) {
+ ThreadPool::PostTaskAndReply(
+ FROM_HERE,
+ BindOnce(&WaitableEvent::Signal, Unretained(&first_reply_is_incoming)),
+ DoNothing());
+ }
+ first_reply_is_incoming.Wait();
+
+ task_environment.FastForwardBy(TimeDelta::FromSeconds(1000));
+
+ // If this test flakes it's because there's an error with MockTimeDomain.
+ EXPECT_EQ(count, 1000);
+
+ // Flush any remaining asynchronous tasks with Unretained() state.
+ task_environment.RunUntilIdle();
+}
+
+TEST_F(TaskEnvironmentTest, MultiThreadedMockTime) {
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ constexpr TimeDelta kOneMs = TimeDelta::FromMilliseconds(1);
+ const TimeTicks start_time = task_environment.NowTicks();
+ const TimeTicks end_time = start_time + TimeDelta::FromMilliseconds(1'000);
+
+ // Last TimeTicks::Now() seen from either contexts.
+ TimeTicks last_main_thread_ticks = start_time;
+ TimeTicks last_thread_pool_ticks = start_time;
+
+ RepeatingClosure post_main_thread_delayed_task;
+ post_main_thread_delayed_task = BindLambdaForTesting([&]() {
+ // Expect that time only moves forward.
+ EXPECT_GE(task_environment.NowTicks(), last_main_thread_ticks);
+
+ // Post four tasks to exercise the system some more but only if this is the
+ // first task at its runtime (otherwise we end up with 4^10'000 tasks by
+ // the end!).
+ if (last_main_thread_ticks < task_environment.NowTicks() &&
+ task_environment.NowTicks() < end_time) {
+ SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, post_main_thread_delayed_task, kOneMs);
+ SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, post_main_thread_delayed_task, kOneMs);
+ SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, post_main_thread_delayed_task, kOneMs);
+ SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, post_main_thread_delayed_task, kOneMs);
+ }
+
+ last_main_thread_ticks = task_environment.NowTicks();
+ });
+
+ RepeatingClosure post_thread_pool_delayed_task;
+ post_thread_pool_delayed_task = BindLambdaForTesting([&]() {
+ // Expect that time only moves forward.
+ EXPECT_GE(task_environment.NowTicks(), last_thread_pool_ticks);
+
+ // Post four tasks to exercise the system some more but only if this is the
+ // first task at its runtime (otherwise we end up with 4^10'000 tasks by
+ // the end!).
+ if (last_thread_pool_ticks < task_environment.NowTicks() &&
+ task_environment.NowTicks() < end_time) {
+ SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, post_thread_pool_delayed_task, kOneMs);
+ SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, post_thread_pool_delayed_task, kOneMs);
+ SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, post_thread_pool_delayed_task, kOneMs);
+ SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, post_thread_pool_delayed_task, kOneMs);
+
+ EXPECT_LT(task_environment.NowTicks(), end_time);
+ }
+
+ last_thread_pool_ticks = task_environment.NowTicks();
+ });
+
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, post_main_thread_delayed_task, kOneMs);
+ ThreadPool::CreateSequencedTaskRunner({})->PostDelayedTask(
+ FROM_HERE, post_thread_pool_delayed_task, kOneMs);
+
+ task_environment.FastForwardUntilNoTasksRemain();
+
+ EXPECT_EQ(last_main_thread_ticks, end_time);
+ EXPECT_EQ(last_thread_pool_ticks, end_time);
+ EXPECT_EQ(task_environment.NowTicks(), end_time);
+}
+
+// This test ensures the implementation of FastForwardBy() doesn't fast-forward
+// beyond the cap it reaches idle with pending delayed tasks further ahead on
+// the main thread.
+TEST_F(TaskEnvironmentTest, MultiThreadedFastForwardBy) {
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ const TimeTicks start_time = task_environment.NowTicks();
+
+ // The 1s delayed task in the pool should run but not the 5s delayed task on
+ // the main thread and fast-forward by should be capped at +2s.
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE),
+ TimeDelta::FromSeconds(5));
+ ThreadPool::PostDelayedTask(FROM_HERE, {}, MakeExpectedRunClosure(FROM_HERE),
+ TimeDelta::FromSeconds(1));
+ task_environment.FastForwardBy(TimeDelta::FromSeconds(2));
+
+ EXPECT_EQ(task_environment.NowTicks(),
+ start_time + TimeDelta::FromSeconds(2));
+}
+
+// Verify that ThreadPoolExecutionMode::QUEUED doesn't prevent running tasks and
+// advancing time on the main thread.
+TEST_F(TaskEnvironmentTest, MultiThreadedMockTimeAndThreadPoolQueuedMode) {
+ TaskEnvironment task_environment(
+ TaskEnvironment::TimeSource::MOCK_TIME,
+ TaskEnvironment::ThreadPoolExecutionMode::QUEUED);
+
+ int count = 0;
+ const TimeTicks start_time = task_environment.NowTicks();
+
+ RunLoop run_loop;
+
+ // Neither of these should run automatically per
+ // ThreadPoolExecutionMode::QUEUED.
+ ThreadPool::PostTask(FROM_HERE,
+ BindLambdaForTesting([&]() { count += 128; }));
+ ThreadPool::PostDelayedTask(FROM_HERE, {},
+ BindLambdaForTesting([&]() { count += 256; }),
+ TimeDelta::FromSeconds(5));
+
+ // Time should auto-advance to +500s in RunLoop::Run() without having to run
+ // the above forcefully QUEUED tasks.
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, BindLambdaForTesting([&]() { count += 1; }));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE,
+ BindLambdaForTesting([&]() {
+ count += 2;
+ run_loop.Quit();
+ }),
+ TimeDelta::FromSeconds(500));
+
+ int expected_value = 0;
+ EXPECT_EQ(expected_value, count);
+ run_loop.Run();
+ expected_value += 1;
+ expected_value += 2;
+ EXPECT_EQ(expected_value, count);
+ EXPECT_EQ(task_environment.NowTicks() - start_time,
+ TimeDelta::FromSeconds(500));
+
+ // Fast-forward through all remaining tasks, this should unblock QUEUED tasks
+ // in the thread pool but shouldn't need to advance time to process them.
+ task_environment.FastForwardUntilNoTasksRemain();
+ expected_value += 128;
+ expected_value += 256;
+ EXPECT_EQ(expected_value, count);
+ EXPECT_EQ(task_environment.NowTicks() - start_time,
+ TimeDelta::FromSeconds(500));
+
+ // Test advancing time to a QUEUED task in the future.
+ ThreadPool::PostDelayedTask(FROM_HERE,
+ BindLambdaForTesting([&]() { count += 512; }),
+ TimeDelta::FromSeconds(5));
+ task_environment.FastForwardBy(TimeDelta::FromSeconds(7));
+ expected_value += 512;
+ EXPECT_EQ(expected_value, count);
+ EXPECT_EQ(task_environment.NowTicks() - start_time,
+ TimeDelta::FromSeconds(507));
+
+ // Confirm that QUEUED mode is still active after the above fast forwarding
+ // (only the main thread task should run from RunLoop).
+ ThreadPool::PostTask(FROM_HERE,
+ BindLambdaForTesting([&]() { count += 1024; }));
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, BindLambdaForTesting([&]() { count += 2048; }));
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
+ RunLoop().RunUntilIdle();
+ expected_value += 2048;
+ EXPECT_EQ(expected_value, count);
+ EXPECT_EQ(task_environment.NowTicks() - start_time,
+ TimeDelta::FromSeconds(507));
+
+ // Run the remaining task to avoid use-after-free on |count| from
+ // ~TaskEnvironment().
+ task_environment.RunUntilIdle();
+ expected_value += 1024;
+ EXPECT_EQ(expected_value, count);
+}
+
+#if defined(OS_WIN)
+// Regression test to ensure that TaskEnvironment enables the MTA in the
+// thread pool (so that the test environment matches that of the browser process
+// and com_init_util.h's assertions are happy in unit tests).
+TEST_F(TaskEnvironmentTest, ThreadPoolPoolAllowsMTA) {
+ TaskEnvironment task_environment;
+ ThreadPool::PostTask(FROM_HERE, BindOnce(&win::AssertComApartmentType,
+ win::ComApartmentType::MTA));
+ task_environment.RunUntilIdle();
+}
+#endif // defined(OS_WIN)
+
+TEST_F(TaskEnvironmentTest, SetsDefaultRunTimeout) {
+ const RunLoop::RunLoopTimeout* old_run_timeout =
+ ScopedRunLoopTimeout::GetTimeoutForCurrentThread();
+
+ {
+ TaskEnvironment task_environment;
+
+ // TaskEnvironment should set a default Run() timeout that fails the
+ // calling test (before test_launcher_timeout()).
+
+ const RunLoop::RunLoopTimeout* run_timeout =
+ ScopedRunLoopTimeout::GetTimeoutForCurrentThread();
+ EXPECT_NE(run_timeout, old_run_timeout);
+ EXPECT_TRUE(run_timeout);
+ if (!debug::BeingDebugged()) {
+ EXPECT_LT(run_timeout->timeout, TestTimeouts::test_launcher_timeout());
+ }
+ static const RepeatingClosure& static_on_timeout = run_timeout->on_timeout;
+ EXPECT_FATAL_FAILURE(static_on_timeout.Run(), "RunLoop::Run() timed out");
+ }
+
+ EXPECT_EQ(ScopedRunLoopTimeout::GetTimeoutForCurrentThread(),
+ old_run_timeout);
+}
+
+TEST_F(TaskEnvironmentTest, DescribePendingMainThreadTasks) {
+ TaskEnvironment task_environment;
+ ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing());
+
+ test::MockLog mock_log;
+ mock_log.StartCapturingLogs();
+
+ EXPECT_CALL(mock_log, Log(::logging::LOG_INFO, _, _, _,
+ HasSubstr("task_environment_unittest.cc")))
+ .WillOnce(Return(true));
+ task_environment.DescribePendingMainThreadTasks();
+
+ task_environment.RunUntilIdle();
+
+ EXPECT_CALL(mock_log, Log(::logging::LOG_INFO, _, _, _,
+ Not(HasSubstr("task_environment_unittest.cc"))))
+ .WillOnce(Return(true));
+ task_environment.DescribePendingMainThreadTasks();
+}
+
+TEST_F(TaskEnvironmentTest, Basic) {
+ TaskEnvironment task_environment(
+ TaskEnvironment::TimeSource::MOCK_TIME,
+ TaskEnvironment::ThreadPoolExecutionMode::QUEUED);
+
+ int counter = 0;
+
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ BindOnce([](int* counter) { *counter += 1; }, Unretained(&counter)));
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ BindOnce([](int* counter) { *counter += 32; }, Unretained(&counter)));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ BindOnce([](int* counter) { *counter += 256; }, Unretained(&counter)),
+ TimeDelta::FromSeconds(3));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ BindOnce([](int* counter) { *counter += 64; }, Unretained(&counter)),
+ TimeDelta::FromSeconds(1));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ BindOnce([](int* counter) { *counter += 1024; }, Unretained(&counter)),
+ TimeDelta::FromMinutes(20));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ BindOnce([](int* counter) { *counter += 4096; }, Unretained(&counter)),
+ TimeDelta::FromDays(20));
+
+ int expected_value = 0;
+ EXPECT_EQ(expected_value, counter);
+ task_environment.RunUntilIdle();
+ expected_value += 1;
+ expected_value += 32;
+ EXPECT_EQ(expected_value, counter);
+
+ task_environment.RunUntilIdle();
+ EXPECT_EQ(expected_value, counter);
+
+ task_environment.FastForwardBy(TimeDelta::FromSeconds(1));
+ expected_value += 64;
+ EXPECT_EQ(expected_value, counter);
+
+ task_environment.FastForwardBy(TimeDelta::FromSeconds(5));
+ expected_value += 256;
+ EXPECT_EQ(expected_value, counter);
+
+ task_environment.FastForwardUntilNoTasksRemain();
+ expected_value += 1024;
+ expected_value += 4096;
+ EXPECT_EQ(expected_value, counter);
+}
+
+TEST_F(TaskEnvironmentTest, RunLoopDriveable) {
+ TaskEnvironment task_environment(
+ TaskEnvironment::TimeSource::MOCK_TIME,
+ TaskEnvironment::ThreadPoolExecutionMode::QUEUED);
+
+ int counter = 0;
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce([](int* counter) { *counter += 1; },
+ Unretained(&counter)));
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce([](int* counter) { *counter += 32; },
+ Unretained(&counter)));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 256; },
+ Unretained(&counter)),
+ TimeDelta::FromSeconds(3));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 64; },
+ Unretained(&counter)),
+ TimeDelta::FromSeconds(1));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 1024; },
+ Unretained(&counter)),
+ TimeDelta::FromMinutes(20));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 4096; },
+ Unretained(&counter)),
+ TimeDelta::FromDays(20));
+
+ int expected_value = 0;
+ EXPECT_EQ(expected_value, counter);
+ RunLoop().RunUntilIdle();
+ expected_value += 1;
+ expected_value += 32;
+ EXPECT_EQ(expected_value, counter);
+
+ RunLoop().RunUntilIdle();
+ EXPECT_EQ(expected_value, counter);
+
+ {
+ RunLoop run_loop;
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(), TimeDelta::FromSeconds(1));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 8192; },
+ Unretained(&counter)),
+ TimeDelta::FromSeconds(1));
+
+ // The QuitClosure() should be ordered between the 64 and the 8192
+ // increments and should preempt the latter.
+ run_loop.Run();
+ expected_value += 64;
+ EXPECT_EQ(expected_value, counter);
+
+ // Running until idle should process the 8192 increment whose delay has
+ // expired in the previous Run().
+ RunLoop().RunUntilIdle();
+ expected_value += 8192;
+ EXPECT_EQ(expected_value, counter);
+ }
+
+ {
+ RunLoop run_loop;
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitWhenIdleClosure(), TimeDelta::FromSeconds(5));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 16384; },
+ Unretained(&counter)),
+ TimeDelta::FromSeconds(5));
+
+ // The QuitWhenIdleClosure() shouldn't preempt equally delayed tasks and as
+ // such the 16384 increment should be processed before quitting.
+ run_loop.Run();
+ expected_value += 256;
+ expected_value += 16384;
+ EXPECT_EQ(expected_value, counter);
+ }
+
+ // Process the remaining tasks (note: do not mimic this elsewhere,
+ // TestMockTimeTaskRunner::FastForwardUntilNoTasksRemain() is a better API to
+ // do this, this is just done here for the purpose of extensively testing the
+ // RunLoop approach).
+
+ // Disable Run() timeout here, otherwise we'll fast-forward to it before we
+ // reach the quit task.
+ ScopedDisableRunLoopTimeout disable_timeout;
+
+ RunLoop run_loop;
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitWhenIdleClosure(), TimeDelta::FromDays(50));
+
+ run_loop.Run();
+ expected_value += 1024;
+ expected_value += 4096;
+ EXPECT_EQ(expected_value, counter);
+}
+
+TEST_F(TaskEnvironmentTest, CancelPendingTask) {
+ TaskEnvironment task_environment(
+ TaskEnvironment::TimeSource::MOCK_TIME,
+ TaskEnvironment::ThreadPoolExecutionMode::QUEUED);
+
+ CancelableOnceClosure task1(BindOnce([]() {}));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, task1.callback(),
+ TimeDelta::FromSeconds(1));
+ EXPECT_TRUE(task_environment.MainThreadIsIdle());
+ EXPECT_EQ(1u, task_environment.GetPendingMainThreadTaskCount());
+ EXPECT_EQ(TimeDelta::FromSeconds(1),
+ task_environment.NextMainThreadPendingTaskDelay());
+ EXPECT_TRUE(task_environment.MainThreadIsIdle());
+ task1.Cancel();
+ EXPECT_TRUE(task_environment.MainThreadIsIdle());
+ EXPECT_EQ(TimeDelta::Max(),
+ task_environment.NextMainThreadPendingTaskDelay());
+
+ CancelableClosure task2(BindRepeating([]() {}));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, task2.callback(),
+ TimeDelta::FromSeconds(1));
+ task2.Cancel();
+ EXPECT_EQ(0u, task_environment.GetPendingMainThreadTaskCount());
+
+ CancelableClosure task3(BindRepeating([]() {}));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, task3.callback(),
+ TimeDelta::FromSeconds(1));
+ task3.Cancel();
+ EXPECT_EQ(TimeDelta::Max(),
+ task_environment.NextMainThreadPendingTaskDelay());
+
+ CancelableClosure task4(BindRepeating([]() {}));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, task4.callback(),
+ TimeDelta::FromSeconds(1));
+ task4.Cancel();
+ EXPECT_TRUE(task_environment.MainThreadIsIdle());
+}
+
+TEST_F(TaskEnvironmentTest, CancelPendingImmediateTask) {
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+ EXPECT_TRUE(task_environment.MainThreadIsIdle());
+
+ CancelableOnceClosure task1(BindOnce([]() {}));
+ ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task1.callback());
+ EXPECT_FALSE(task_environment.MainThreadIsIdle());
+
+ task1.Cancel();
+ EXPECT_TRUE(task_environment.MainThreadIsIdle());
+}
+
+TEST_F(TaskEnvironmentTest, NoFastForwardToCancelledTask) {
+ TaskEnvironment task_environment(
+ TaskEnvironment::TimeSource::MOCK_TIME,
+ TaskEnvironment::ThreadPoolExecutionMode::QUEUED);
+
+ TimeTicks start_time = task_environment.NowTicks();
+ CancelableClosure task(BindRepeating([]() {}));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, task.callback(),
+ TimeDelta::FromSeconds(1));
+ EXPECT_EQ(TimeDelta::FromSeconds(1),
+ task_environment.NextMainThreadPendingTaskDelay());
+ task.Cancel();
+ task_environment.FastForwardUntilNoTasksRemain();
+ EXPECT_EQ(start_time, task_environment.NowTicks());
+}
+
+TEST_F(TaskEnvironmentTest, NextTaskIsDelayed) {
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ EXPECT_FALSE(task_environment.NextTaskIsDelayed());
+ CancelableClosure task(BindRepeating([]() {}));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, task.callback(),
+ TimeDelta::FromSeconds(1));
+ EXPECT_TRUE(task_environment.NextTaskIsDelayed());
+ task.Cancel();
+ EXPECT_FALSE(task_environment.NextTaskIsDelayed());
+
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, BindOnce([]() {}),
+ TimeDelta::FromSeconds(2));
+ EXPECT_TRUE(task_environment.NextTaskIsDelayed());
+ task_environment.FastForwardUntilNoTasksRemain();
+ EXPECT_FALSE(task_environment.NextTaskIsDelayed());
+
+ ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, BindOnce([]() {}));
+ EXPECT_FALSE(task_environment.NextTaskIsDelayed());
+}
+
+TEST_F(TaskEnvironmentTest, NextMainThreadPendingTaskDelayWithImmediateTask) {
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ EXPECT_EQ(TimeDelta::Max(),
+ task_environment.NextMainThreadPendingTaskDelay());
+ ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, BindOnce([]() {}));
+ EXPECT_EQ(TimeDelta(), task_environment.NextMainThreadPendingTaskDelay());
+}
+
+TEST_F(TaskEnvironmentTest, TimeSourceMockTimeAlsoMocksNow) {
+ TaskEnvironment task_environment(TaskEnvironment::TimeSource::MOCK_TIME);
+
+ const TimeTicks start_ticks = task_environment.NowTicks();
+ EXPECT_EQ(TimeTicks::Now(), start_ticks);
+
+ const Time start_time = Time::Now();
+
+ constexpr TimeDelta kDelay = TimeDelta::FromSeconds(10);
+ task_environment.FastForwardBy(kDelay);
+ EXPECT_EQ(TimeTicks::Now(), start_ticks + kDelay);
+ EXPECT_EQ(Time::Now(), start_time + kDelay);
+}
+
+TEST_F(TaskEnvironmentTest, SingleThread) {
+ SingleThreadTaskEnvironment task_environment;
+ EXPECT_THAT(ThreadPoolInstance::Get(), IsNull());
+
+ bool ran = false;
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindLambdaForTesting([&]() { ran = true; }));
+ RunLoop().RunUntilIdle();
+ EXPECT_TRUE(ran);
+
+ EXPECT_DCHECK_DEATH(ThreadPool::PostTask(FROM_HERE, {}, DoNothing()));
+}
+
+// Verify that traits other than ThreadingMode can be applied to
+// SingleThreadTaskEnvironment.
+TEST_F(TaskEnvironmentTest, SingleThreadMockTime) {
+ SingleThreadTaskEnvironment task_environment(
+ TaskEnvironment::TimeSource::MOCK_TIME);
+
+ const TimeTicks start_time = TimeTicks::Now();
+
+ constexpr TimeDelta kDelay = TimeDelta::FromSeconds(100);
+
+ int counter = 0;
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::BindLambdaForTesting([&]() { counter += 1; }), kDelay);
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindLambdaForTesting([&]() { counter += 2; }));
+
+ int expected_value = 0;
+ EXPECT_EQ(expected_value, counter);
+
+ task_environment.RunUntilIdle();
+ expected_value += 2;
+ EXPECT_EQ(expected_value, counter);
+
+ task_environment.FastForwardUntilNoTasksRemain();
+ expected_value += 1;
+ EXPECT_EQ(expected_value, counter);
+ EXPECT_EQ(TimeTicks::Now(), start_time + kDelay);
+}
+
+#if defined(OS_WIN)
+namespace {
+
+enum class ApartmentType {
+ kSTA,
+ kMTA,
+};
+
+void InitializeSTAApartment() {
+ base::win::ScopedCOMInitializer initializer;
+ EXPECT_TRUE(initializer.Succeeded());
+}
+
+void InitializeMTAApartment() {
+ base::win::ScopedCOMInitializer initializer(
+ base::win::ScopedCOMInitializer::kMTA);
+ EXPECT_TRUE(initializer.Succeeded());
+}
+
+void InitializeCOMOnWorker(
+ TaskEnvironment::ThreadPoolCOMEnvironment com_environment,
+ ApartmentType apartment_type) {
+ TaskEnvironment task_environment(com_environment);
+ ThreadPool::PostTask(FROM_HERE, BindOnce(apartment_type == ApartmentType::kSTA
+ ? &InitializeSTAApartment
+ : &InitializeMTAApartment));
+ task_environment.RunUntilIdle();
+}
+
+} // namespace
+
+TEST_F(TaskEnvironmentTest, DefaultCOMEnvironment) {
+ // Attempt to initialize an MTA COM apartment. Expect this to succeed since
+ // the thread is already in an MTA apartment.
+ InitializeCOMOnWorker(TaskEnvironment::ThreadPoolCOMEnvironment::DEFAULT,
+ ApartmentType::kMTA);
+
+ // Attempt to initialize an STA COM apartment. Expect this to fail since the
+ // thread is already in an MTA apartment.
+ EXPECT_DCHECK_DEATH(InitializeCOMOnWorker(
+ TaskEnvironment::ThreadPoolCOMEnvironment::DEFAULT, ApartmentType::kSTA));
+}
+
+TEST_F(TaskEnvironmentTest, NoCOMEnvironment) {
+ // Attempt to initialize both MTA and STA COM apartments. Both should succeed
+ // when the thread is not already in an apartment.
+ InitializeCOMOnWorker(TaskEnvironment::ThreadPoolCOMEnvironment::NONE,
+ ApartmentType::kMTA);
+ InitializeCOMOnWorker(TaskEnvironment::ThreadPoolCOMEnvironment::NONE,
+ ApartmentType::kSTA);
+}
+#endif
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/task_runner_test_template.cc b/chromium/base/test/task_runner_test_template.cc
new file mode 100644
index 00000000000..e92e8467c6c
--- /dev/null
+++ b/chromium/base/test/task_runner_test_template.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/task_runner_test_template.h"
+
+namespace base {
+
+namespace test {
+
+TaskTracker::TaskTracker() : task_runs_(0), task_runs_cv_(&lock_) {}
+
+TaskTracker::~TaskTracker() = default;
+
+RepeatingClosure TaskTracker::WrapTask(RepeatingClosure task, int i) {
+ return BindRepeating(&TaskTracker::RunTask, this, std::move(task), i);
+}
+
+void TaskTracker::RunTask(RepeatingClosure task, int i) {
+ AutoLock lock(lock_);
+ if (!task.is_null()) {
+ task.Run();
+ }
+ ++task_run_counts_[i];
+ ++task_runs_;
+ task_runs_cv_.Signal();
+}
+
+std::map<int, int> TaskTracker::GetTaskRunCounts() const {
+ AutoLock lock(lock_);
+ return task_run_counts_;
+}
+
+void TaskTracker::WaitForCompletedTasks(int count) {
+ AutoLock lock(lock_);
+ while (task_runs_ < count)
+ task_runs_cv_.Wait();
+}
+
+} // namespace test
+
+} // namespace base
diff --git a/chromium/base/test/task_runner_test_template.h b/chromium/base/test/task_runner_test_template.h
new file mode 100644
index 00000000000..37acde16686
--- /dev/null
+++ b/chromium/base/test/task_runner_test_template.h
@@ -0,0 +1,170 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines tests that implementations of TaskRunner should
+// pass in order to be conformant, as well as test cases for optional behavior.
+// Here's how you use it to test your implementation.
+//
+// Say your class is called MyTaskRunner. Then you need to define a
+// class called MyTaskRunnerTestDelegate in my_task_runner_unittest.cc
+// like this:
+//
+// class MyTaskRunnerTestDelegate {
+// public:
+// // Tasks posted to the task runner after this and before
+// // StopTaskRunner() is called is called should run successfully.
+// void StartTaskRunner() {
+// ...
+// }
+//
+// // Should return the task runner implementation. Only called
+// // after StartTaskRunner and before StopTaskRunner.
+// scoped_refptr<MyTaskRunner> GetTaskRunner() {
+// ...
+// }
+//
+// // Stop the task runner and make sure all tasks posted before
+// // this is called are run. Caveat: delayed tasks are not run,
+ // they're simply deleted.
+// void StopTaskRunner() {
+// ...
+// }
+// };
+//
+// The TaskRunnerTest test harness will have a member variable of
+// this delegate type and will call its functions in the various
+// tests.
+//
+// Then you simply #include this file as well as gtest.h and add the
+// following statement to my_task_runner_unittest.cc:
+//
+// INSTANTIATE_TYPED_TEST_SUITE_P(
+// MyTaskRunner, TaskRunnerTest, MyTaskRunnerTestDelegate);
+//
+// Easy!
+
+#ifndef BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
+#define BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
+
+#include <cstddef>
+#include <map>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/task_runner.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace test {
+
+// Utility class that keeps track of how many times particular tasks
+// are run.
+class TaskTracker : public RefCountedThreadSafe<TaskTracker> {
+ public:
+ TaskTracker();
+
+ // Returns a closure that runs the given task and increments the run
+ // count of |i| by one. |task| may be null. It is guaranteed that
+ // only one task wrapped by a given tracker will be run at a time.
+ RepeatingClosure WrapTask(RepeatingClosure task, int i);
+
+ std::map<int, int> GetTaskRunCounts() const;
+
+ // Returns after the tracker observes a total of |count| task completions.
+ void WaitForCompletedTasks(int count);
+
+ private:
+ friend class RefCountedThreadSafe<TaskTracker>;
+
+ ~TaskTracker();
+
+ void RunTask(RepeatingClosure task, int i);
+
+ mutable Lock lock_;
+ std::map<int, int> task_run_counts_;
+ int task_runs_;
+ ConditionVariable task_runs_cv_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskTracker);
+};
+
+} // namespace test
+
+template <typename TaskRunnerTestDelegate>
+class TaskRunnerTest : public testing::Test {
+ protected:
+ TaskRunnerTest() : task_tracker_(base::MakeRefCounted<test::TaskTracker>()) {}
+
+ const scoped_refptr<test::TaskTracker> task_tracker_;
+ TaskRunnerTestDelegate delegate_;
+};
+
+TYPED_TEST_SUITE_P(TaskRunnerTest);
+
+// We can't really test much, since TaskRunner provides very few
+// guarantees.
+
+// Post a bunch of tasks to the task runner. They should all
+// complete.
+TYPED_TEST_P(TaskRunnerTest, Basic) {
+ std::map<int, int> expected_task_run_counts;
+
+ this->delegate_.StartTaskRunner();
+ scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
+ // Post each ith task i+1 times.
+ for (int i = 0; i < 20; ++i) {
+ RepeatingClosure ith_task =
+ this->task_tracker_->WrapTask(RepeatingClosure(), i);
+ for (int j = 0; j < i + 1; ++j) {
+ task_runner->PostTask(FROM_HERE, ith_task);
+ ++expected_task_run_counts[i];
+ }
+ }
+ this->delegate_.StopTaskRunner();
+
+ EXPECT_EQ(expected_task_run_counts,
+ this->task_tracker_->GetTaskRunCounts());
+}
+
+// Post a bunch of delayed tasks to the task runner. They should all
+// complete.
+TYPED_TEST_P(TaskRunnerTest, Delayed) {
+ std::map<int, int> expected_task_run_counts;
+ int expected_total_tasks = 0;
+
+ this->delegate_.StartTaskRunner();
+ scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
+ // Post each ith task i+1 times with delays from 0-i.
+ for (int i = 0; i < 20; ++i) {
+ RepeatingClosure ith_task =
+ this->task_tracker_->WrapTask(RepeatingClosure(), i);
+ for (int j = 0; j < i + 1; ++j) {
+ task_runner->PostDelayedTask(
+ FROM_HERE, ith_task, base::TimeDelta::FromMilliseconds(j));
+ ++expected_task_run_counts[i];
+ ++expected_total_tasks;
+ }
+ }
+ this->task_tracker_->WaitForCompletedTasks(expected_total_tasks);
+ this->delegate_.StopTaskRunner();
+
+ EXPECT_EQ(expected_task_run_counts,
+ this->task_tracker_->GetTaskRunCounts());
+}
+
+// The TaskRunnerTest test case verifies behaviour that is expected from a
+// task runner in order to be conformant.
+REGISTER_TYPED_TEST_SUITE_P(TaskRunnerTest, Basic, Delayed);
+
+} // namespace base
+
+#endif // BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
diff --git a/chromium/base/test/test_child_process.cc b/chromium/base/test/test_child_process.cc
new file mode 100644
index 00000000000..ce158561163
--- /dev/null
+++ b/chromium/base/test/test_child_process.cc
@@ -0,0 +1,43 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Simple testing command, used to exercise child process launcher calls.
+//
+// Usage:
+// echo_test_helper [-x exit_code] arg0 arg1 arg2...
+// Prints arg0..n to stdout with space delimiters between args,
+// returning "exit_code" if -x is specified.
+//
+// echo_test_helper -e env_var
+// Prints the environmental variable |env_var| to stdout.
+int main(int argc, char** argv) {
+ if (strcmp(argv[1], "-e") == 0) {
+ if (argc != 3) {
+ return 1;
+ }
+
+ const char* env = getenv(argv[2]);
+ if (env != NULL) {
+ printf("%s", env);
+ }
+ } else {
+ int return_code = 0;
+ int start_idx = 1;
+
+ if (strcmp(argv[1], "-x") == 0) {
+ return_code = atoi(argv[2]);
+ start_idx = 3;
+ }
+
+ for (int i = start_idx; i < argc; ++i) {
+ printf((i < argc - 1 ? "%s " : "%s"), argv[i]);
+ }
+
+ return return_code;
+ }
+}
diff --git a/chromium/base/test/test_discardable_memory_allocator.cc b/chromium/base/test/test_discardable_memory_allocator.cc
new file mode 100644
index 00000000000..26bc5b036a8
--- /dev/null
+++ b/chromium/base/test/test_discardable_memory_allocator.cc
@@ -0,0 +1,67 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_discardable_memory_allocator.h"
+
+#include <cstdint>
+#include <cstring>
+
+#include "base/check.h"
+#include "base/memory/discardable_memory.h"
+#include "base/memory/ptr_util.h"
+
+namespace base {
+namespace {
+
+class DiscardableMemoryImpl : public DiscardableMemory {
+ public:
+ explicit DiscardableMemoryImpl(size_t size)
+ : data_(new uint8_t[size]), size_(size) {}
+
+ // Overridden from DiscardableMemory:
+ bool Lock() override {
+ DCHECK(!is_locked_);
+ is_locked_ = true;
+ return false;
+ }
+
+ void Unlock() override {
+ DCHECK(is_locked_);
+ is_locked_ = false;
+ // Force eviction to catch clients not correctly checking the return value
+ // of Lock().
+ memset(data_.get(), 0, size_);
+ }
+
+ void* data() const override {
+ DCHECK(is_locked_);
+ return data_.get();
+ }
+
+ void DiscardForTesting() override {}
+
+ trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump(
+ const char* name,
+ trace_event::ProcessMemoryDump* pmd) const override {
+ return nullptr;
+ }
+
+ private:
+ bool is_locked_ = true;
+ std::unique_ptr<uint8_t[]> data_;
+ size_t size_;
+};
+
+} // namespace
+
+std::unique_ptr<DiscardableMemory>
+TestDiscardableMemoryAllocator::AllocateLockedDiscardableMemory(size_t size) {
+ return std::make_unique<DiscardableMemoryImpl>(size);
+}
+
+size_t TestDiscardableMemoryAllocator::GetBytesAllocated() const {
+ return 0U;
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_discardable_memory_allocator.h b/chromium/base/test/test_discardable_memory_allocator.h
new file mode 100644
index 00000000000..ba9719ada4a
--- /dev/null
+++ b/chromium/base/test/test_discardable_memory_allocator.h
@@ -0,0 +1,38 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_DISCARDABLE_MEMORY_ALLOCATOR_H_
+#define BASE_TEST_TEST_DISCARDABLE_MEMORY_ALLOCATOR_H_
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "base/memory/discardable_memory_allocator.h"
+
+namespace base {
+
+// TestDiscardableMemoryAllocator is a simple DiscardableMemoryAllocator
+// implementation that can be used for testing. It allocates one-shot
+// DiscardableMemory instances backed by heap memory.
+class TestDiscardableMemoryAllocator : public DiscardableMemoryAllocator {
+ public:
+ TestDiscardableMemoryAllocator() = default;
+
+ // Overridden from DiscardableMemoryAllocator:
+ std::unique_ptr<DiscardableMemory> AllocateLockedDiscardableMemory(
+ size_t size) override;
+
+ size_t GetBytesAllocated() const override;
+
+ void ReleaseFreeMemory() override {
+ // Do nothing since it is backed by heap memory.
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestDiscardableMemoryAllocator);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_TEST_DISCARDABLE_MEMORY_ALLOCATOR_H_
diff --git a/chromium/base/test/test_file_util.cc b/chromium/base/test/test_file_util.cc
new file mode 100644
index 00000000000..8dafc58a7df
--- /dev/null
+++ b/chromium/base/test/test_file_util.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+bool EvictFileFromSystemCacheWithRetry(const FilePath& path) {
+ const int kCycles = 10;
+ const TimeDelta kDelay = TestTimeouts::action_timeout() / kCycles;
+ for (int i = 0; i < kCycles; i++) {
+ if (EvictFileFromSystemCache(path))
+ return true;
+ PlatformThread::Sleep(kDelay);
+ }
+ return false;
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_file_util.h b/chromium/base/test/test_file_util.h
new file mode 100644
index 00000000000..f9951b0fb14
--- /dev/null
+++ b/chromium/base/test/test_file_util.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_FILE_UTIL_H_
+#define BASE_TEST_TEST_FILE_UTIL_H_
+
+// File utility functions used only by tests.
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+
+#if defined(OS_ANDROID)
+#include <jni.h>
+#endif
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+// Clear a specific file from the system cache like EvictFileFromSystemCache,
+// but on failure it will sleep and retry. On the Windows buildbots, eviction
+// can fail if the file is marked in use, and this will throw off timings that
+// rely on uncached files.
+bool EvictFileFromSystemCacheWithRetry(const FilePath& file);
+
+// Wrapper over base::Delete. On Windows repeatedly invokes Delete in case
+// of failure to workaround Windows file locking semantics. Returns true on
+// success.
+bool DieFileDie(const FilePath& file, bool recurse);
+
+// Synchronize all the dirty pages from the page cache to disk (on POSIX
+// systems). The Windows analogy for this operation is to 'Flush file buffers'.
+// Note: This is currently implemented as a no-op on Windows.
+void SyncPageCacheToDisk();
+
+// Clear a specific file from the system cache. After this call, trying
+// to access this file will result in a cold load from the hard drive.
+bool EvictFileFromSystemCache(const FilePath& file);
+
+#if defined(OS_WIN)
+// Deny |permission| on the file |path| for the current user. |permission| is an
+// ACCESS_MASK structure which is defined in
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa374892.aspx
+// Refer to https://msdn.microsoft.com/en-us/library/aa822867.aspx for a list of
+// possible values.
+bool DenyFilePermission(const FilePath& path, DWORD permission);
+#endif // defined(OS_WIN)
+
+// For testing, make the file unreadable or unwritable.
+// In POSIX, this does not apply to the root user.
+bool MakeFileUnreadable(const FilePath& path) WARN_UNUSED_RESULT;
+bool MakeFileUnwritable(const FilePath& path) WARN_UNUSED_RESULT;
+
+// Saves the current permissions for a path, and restores it on destruction.
+class FilePermissionRestorer {
+ public:
+ explicit FilePermissionRestorer(const FilePath& path);
+ ~FilePermissionRestorer();
+
+ private:
+ const FilePath path_;
+ void* info_; // The opaque stored permission information.
+ size_t length_; // The length of the stored permission information.
+
+ DISALLOW_COPY_AND_ASSIGN(FilePermissionRestorer);
+};
+
+#if defined(OS_ANDROID)
+// Insert an image file into the MediaStore, and retrieve the content URI for
+// testing purpose.
+FilePath InsertImageIntoMediaStore(const FilePath& path);
+#endif // defined(OS_ANDROID)
+
+} // namespace base
+
+#endif // BASE_TEST_TEST_FILE_UTIL_H_
diff --git a/chromium/base/test/test_file_util_android.cc b/chromium/base/test/test_file_util_android.cc
new file mode 100644
index 00000000000..fc0beb3faa8
--- /dev/null
+++ b/chromium/base/test/test_file_util_android.cc
@@ -0,0 +1,26 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/files/file_path.h"
+#include "base/test/base_unittests_jni_headers/ContentUriTestUtils_jni.h"
+
+using base::android::ScopedJavaLocalRef;
+
+namespace base {
+
+FilePath InsertImageIntoMediaStore(const FilePath& path) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> j_path =
+ base::android::ConvertUTF8ToJavaString(env, path.value());
+ ScopedJavaLocalRef<jstring> j_uri =
+ Java_ContentUriTestUtils_insertImageIntoMediaStore(env, j_path);
+ std::string uri = base::android::ConvertJavaStringToUTF8(j_uri);
+ return FilePath(uri);
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_file_util_linux.cc b/chromium/base/test/test_file_util_linux.cc
new file mode 100644
index 00000000000..85fb69fdfbe
--- /dev/null
+++ b/chromium/base/test/test_file_util_linux.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#if defined(OS_ANDROID)
+#include <asm/unistd.h>
+#include <errno.h>
+#include <linux/fadvise.h>
+#include <sys/syscall.h>
+#endif
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
+#include "base/notreached.h"
+
+namespace base {
+
+// Inconveniently, the NDK doesn't provide for posix_fadvise
+// until native API level = 21, which we don't use yet, so provide a wrapper, at
+// least on ARM32
+#if defined(OS_ANDROID) && __ANDROID_API__ < 21
+
+namespace {
+int posix_fadvise(int fd, off_t offset, off_t len, int advice) {
+#if defined(ARCH_CPU_ARMEL)
+ // Note that the syscall argument order on ARM is different from the C
+ // function; this is helpfully documented in the Linux posix_fadvise manpage.
+ return syscall(__NR_arm_fadvise64_64, fd, advice,
+ 0, // Upper 32-bits for offset
+ offset,
+ 0, // Upper 32-bits for length
+ len);
+#endif
+ NOTIMPLEMENTED();
+ return ENOSYS;
+}
+
+} // namespace
+
+#endif // OS_ANDROID
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+ ScopedFD fd(open(file.value().c_str(), O_RDONLY));
+ if (!fd.is_valid())
+ return false;
+ if (fdatasync(fd.get()) != 0)
+ return false;
+ if (posix_fadvise(fd.get(), 0, 0, POSIX_FADV_DONTNEED) != 0)
+ return false;
+ return true;
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_file_util_mac.cc b/chromium/base/test/test_file_util_mac.cc
new file mode 100644
index 00000000000..174a31db254
--- /dev/null
+++ b/chromium/base/test/test_file_util_mac.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <sys/mman.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include "base/files/file_util.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/logging.h"
+
+namespace base {
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+ // There aren't any really direct ways to purge a file from the UBC. From
+ // talking with Amit Singh, the safest is to mmap the file with MAP_FILE (the
+ // default) + MAP_SHARED, then do an msync to invalidate the memory. The next
+ // open should then have to load the file from disk.
+
+ int64_t length;
+ if (!GetFileSize(file, &length)) {
+ DLOG(ERROR) << "failed to get size of " << file.value();
+ return false;
+ }
+
+ // When a file is empty, we do not need to evict it from cache.
+ // In fact, an attempt to map it to memory will result in error.
+ if (length == 0) {
+ DLOG(WARNING) << "file size is zero, will not attempt to map to memory";
+ return true;
+ }
+
+ MemoryMappedFile mapped_file;
+ if (!mapped_file.Initialize(file)) {
+ DLOG(WARNING) << "failed to memory map " << file.value();
+ return false;
+ }
+
+ if (msync(const_cast<uint8_t*>(mapped_file.data()), mapped_file.length(),
+ MS_INVALIDATE) != 0) {
+ DLOG(WARNING) << "failed to invalidate memory map of " << file.value()
+ << ", errno: " << errno;
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_file_util_posix.cc b/chromium/base/test/test_file_util_posix.cc
new file mode 100644
index 00000000000..02c214a4214
--- /dev/null
+++ b/chromium/base/test/test_file_util_posix.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/check_op.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/notreached.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace {
+
+// Deny |permission| on the file |path|.
+bool DenyFilePermission(const FilePath& path, mode_t permission) {
+ stat_wrapper_t stat_buf;
+ if (File::Stat(path.value().c_str(), &stat_buf) != 0)
+ return false;
+ stat_buf.st_mode &= ~permission;
+
+ int rv = HANDLE_EINTR(chmod(path.value().c_str(), stat_buf.st_mode));
+ return rv == 0;
+}
+
+// Gets a blob indicating the permission information for |path|.
+// |length| is the length of the blob. Zero on failure.
+// Returns the blob pointer, or NULL on failure.
+void* GetPermissionInfo(const FilePath& path, size_t* length) {
+ DCHECK(length);
+ *length = 0;
+
+ stat_wrapper_t stat_buf;
+ if (File::Stat(path.value().c_str(), &stat_buf) != 0)
+ return nullptr;
+
+ *length = sizeof(mode_t);
+ mode_t* mode = new mode_t;
+ *mode = stat_buf.st_mode & ~S_IFMT; // Filter out file/path kind.
+
+ return mode;
+}
+
+// Restores the permission information for |path|, given the blob retrieved
+// using |GetPermissionInfo()|.
+// |info| is the pointer to the blob.
+// |length| is the length of the blob.
+// Either |info| or |length| may be NULL/0, in which case nothing happens.
+bool RestorePermissionInfo(const FilePath& path, void* info, size_t length) {
+ if (!info || (length == 0))
+ return false;
+
+ DCHECK_EQ(sizeof(mode_t), length);
+ mode_t* mode = reinterpret_cast<mode_t*>(info);
+
+ int rv = HANDLE_EINTR(chmod(path.value().c_str(), *mode));
+
+ delete mode;
+
+ return rv == 0;
+}
+
+} // namespace
+
+bool DieFileDie(const FilePath& file, bool recurse) {
+ // There is no need to workaround Windows problems on POSIX.
+ // Just pass-through.
+ return DeleteFile(file, recurse);
+}
+
+void SyncPageCacheToDisk() {
+ // On Linux (and Android) the sync(2) call waits for I/O completions.
+ sync();
+}
+
+#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
+bool EvictFileFromSystemCache(const FilePath& file) {
+ // There doesn't seem to be a POSIX way to cool the disk cache.
+ NOTIMPLEMENTED();
+ return false;
+}
+#endif
+
+bool MakeFileUnreadable(const FilePath& path) {
+ return DenyFilePermission(path, S_IRUSR | S_IRGRP | S_IROTH);
+}
+
+bool MakeFileUnwritable(const FilePath& path) {
+ return DenyFilePermission(path, S_IWUSR | S_IWGRP | S_IWOTH);
+}
+
+FilePermissionRestorer::FilePermissionRestorer(const FilePath& path)
+ : path_(path), info_(nullptr), length_(0) {
+ info_ = GetPermissionInfo(path_, &length_);
+ DCHECK(info_ != nullptr);
+ DCHECK_NE(0u, length_);
+}
+
+FilePermissionRestorer::~FilePermissionRestorer() {
+ if (!RestorePermissionInfo(path_, info_, length_))
+ NOTREACHED();
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_file_util_win.cc b/chromium/base/test/test_file_util_win.cc
new file mode 100644
index 00000000000..d2a861b23aa
--- /dev/null
+++ b/chromium/base/test/test_file_util_win.cc
@@ -0,0 +1,189 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <aclapi.h>
+#include <stddef.h>
+#include <wchar.h>
+#include <windows.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/check_op.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/memory/ptr_util.h"
+#include "base/notreached.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/threading/platform_thread.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/shlwapi.h"
+
+namespace base {
+
+namespace {
+
+struct PermissionInfo {
+ PSECURITY_DESCRIPTOR security_descriptor;
+ ACL dacl;
+};
+
+// Gets a blob indicating the permission information for |path|.
+// |length| is the length of the blob. Zero on failure.
+// Returns the blob pointer, or NULL on failure.
+void* GetPermissionInfo(const FilePath& path, size_t* length) {
+ DCHECK(length != NULL);
+ *length = 0;
+ PACL dacl = NULL;
+ PSECURITY_DESCRIPTOR security_descriptor;
+ if (GetNamedSecurityInfo(path.value().c_str(), SE_FILE_OBJECT,
+ DACL_SECURITY_INFORMATION, NULL, NULL, &dacl, NULL,
+ &security_descriptor) != ERROR_SUCCESS) {
+ return NULL;
+ }
+ DCHECK(dacl != NULL);
+
+ *length = sizeof(PSECURITY_DESCRIPTOR) + dacl->AclSize;
+ PermissionInfo* info = reinterpret_cast<PermissionInfo*>(new char[*length]);
+ info->security_descriptor = security_descriptor;
+ memcpy(&info->dacl, dacl, dacl->AclSize);
+
+ return info;
+}
+
+// Restores the permission information for |path|, given the blob retrieved
+// using |GetPermissionInfo()|.
+// |info| is the pointer to the blob.
+// |length| is the length of the blob.
+// Either |info| or |length| may be NULL/0, in which case nothing happens.
+bool RestorePermissionInfo(const FilePath& path, void* info, size_t length) {
+ if (!info || !length)
+ return false;
+
+ PermissionInfo* perm = reinterpret_cast<PermissionInfo*>(info);
+
+ DWORD rc = SetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+ SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
+ NULL, NULL, &perm->dacl, NULL);
+ LocalFree(perm->security_descriptor);
+
+ char* char_array = reinterpret_cast<char*>(info);
+ delete [] char_array;
+
+ return rc == ERROR_SUCCESS;
+}
+
+std::unique_ptr<wchar_t[]> ToCStr(const std::basic_string<wchar_t>& str) {
+ size_t size = str.size() + 1;
+ std::unique_ptr<wchar_t[]> ptr = std::make_unique<wchar_t[]>(size);
+ wcsncpy(ptr.get(), str.c_str(), size);
+ return ptr;
+}
+
+} // namespace
+
+bool DieFileDie(const FilePath& file, bool recurse) {
+ // It turns out that to not induce flakiness a long timeout is needed.
+ const int kIterations = 25;
+ const TimeDelta kTimeout = TimeDelta::FromSeconds(10) / kIterations;
+
+ if (!PathExists(file))
+ return true;
+
+ // Sometimes Delete fails, so try a few more times. Divide the timeout
+ // into short chunks, so that if a try succeeds, we won't delay the test
+ // for too long.
+ for (int i = 0; i < kIterations; ++i) {
+ if (DeleteFile(file, recurse))
+ return true;
+ PlatformThread::Sleep(kTimeout);
+ }
+ return false;
+}
+
+void SyncPageCacheToDisk() {
+ // Approximating this with noop. The proper implementation would require
+ // administrator privilege:
+ // https://docs.microsoft.com/en-us/windows/desktop/api/FileAPI/nf-fileapi-flushfilebuffers
+}
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+ win::ScopedHandle file_handle(
+ CreateFile(file.value().c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL));
+ if (!file_handle.IsValid())
+ return false;
+
+ // Re-write the file time information to trigger cache eviction for the file.
+ // This function previously overwrote the entire file without buffering, but
+ // local experimentation validates this simplified and *much* faster approach:
+ // [1] Sysinternals RamMap no longer lists these files as cached afterwards.
+ // [2] Telemetry performance test startup.cold.blank_page reports sane values.
+ BY_HANDLE_FILE_INFORMATION bhi = {0};
+ CHECK(::GetFileInformationByHandle(file_handle.Get(), &bhi));
+ CHECK(::SetFileTime(file_handle.Get(), &bhi.ftCreationTime,
+ &bhi.ftLastAccessTime, &bhi.ftLastWriteTime));
+ return true;
+}
+
+// Deny |permission| on the file |path|, for the current user.
+bool DenyFilePermission(const FilePath& path, DWORD permission) {
+ PACL old_dacl;
+ PSECURITY_DESCRIPTOR security_descriptor;
+
+ std::unique_ptr<TCHAR[]> path_ptr = ToCStr(path.value().c_str());
+ if (GetNamedSecurityInfo(path_ptr.get(), SE_FILE_OBJECT,
+ DACL_SECURITY_INFORMATION, nullptr, nullptr,
+ &old_dacl, nullptr,
+ &security_descriptor) != ERROR_SUCCESS) {
+ return false;
+ }
+
+ std::unique_ptr<TCHAR[]> current_user = ToCStr(std::wstring(L"CURRENT_USER"));
+ EXPLICIT_ACCESS new_access = {
+ permission,
+ DENY_ACCESS,
+ 0,
+ {nullptr, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_NAME, TRUSTEE_IS_USER,
+ current_user.get()}};
+
+ PACL new_dacl;
+ if (SetEntriesInAcl(1, &new_access, old_dacl, &new_dacl) != ERROR_SUCCESS) {
+ LocalFree(security_descriptor);
+ return false;
+ }
+
+ DWORD rc = SetNamedSecurityInfo(path_ptr.get(), SE_FILE_OBJECT,
+ DACL_SECURITY_INFORMATION, nullptr, nullptr,
+ new_dacl, nullptr);
+ LocalFree(security_descriptor);
+ LocalFree(new_dacl);
+
+ return rc == ERROR_SUCCESS;
+}
+
+bool MakeFileUnreadable(const FilePath& path) {
+ return DenyFilePermission(path, GENERIC_READ);
+}
+
+bool MakeFileUnwritable(const FilePath& path) {
+ return DenyFilePermission(path, GENERIC_WRITE);
+}
+
+FilePermissionRestorer::FilePermissionRestorer(const FilePath& path)
+ : path_(path), info_(NULL), length_(0) {
+ info_ = GetPermissionInfo(path_, &length_);
+ DCHECK(info_ != NULL);
+ DCHECK_NE(0u, length_);
+}
+
+FilePermissionRestorer::~FilePermissionRestorer() {
+ if (!RestorePermissionInfo(path_, info_, length_))
+ NOTREACHED();
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_io_thread.cc b/chromium/base/test/test_io_thread.cc
new file mode 100644
index 00000000000..15e4fe015c6
--- /dev/null
+++ b/chromium/base/test/test_io_thread.cc
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_io_thread.h"
+
+#include "base/check.h"
+#include "base/message_loop/message_pump_type.h"
+
+namespace base {
+
+TestIOThread::TestIOThread(Mode mode)
+ : io_thread_("test_io_thread"), io_thread_started_(false) {
+ switch (mode) {
+ case kAutoStart:
+ Start();
+ return;
+ case kManualStart:
+ return;
+ }
+ CHECK(false) << "Invalid mode";
+}
+
+TestIOThread::~TestIOThread() {
+ Stop();
+}
+
+void TestIOThread::Start() {
+ CHECK(!io_thread_started_);
+ io_thread_started_ = true;
+ CHECK(io_thread_.StartWithOptions(
+ base::Thread::Options(base::MessagePumpType::IO, 0)));
+}
+
+void TestIOThread::Stop() {
+ // Note: It's okay to call |Stop()| even if the thread isn't running.
+ io_thread_.Stop();
+ io_thread_started_ = false;
+}
+
+void TestIOThread::PostTask(const Location& from_here, base::OnceClosure task) {
+ task_runner()->PostTask(from_here, std::move(task));
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_io_thread.h b/chromium/base/test/test_io_thread.h
new file mode 100644
index 00000000000..c72d4fa509c
--- /dev/null
+++ b/chromium/base/test/test_io_thread.h
@@ -0,0 +1,56 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_IO_THREAD_H_
+#define BASE_TEST_TEST_IO_THREAD_H_
+
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/task_runner.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// Create and run an IO thread with a MessageLoop, and
+// making the MessageLoop accessible from its client.
+// It also provides some ideomatic API like PostTaskAndWait().
+//
+// This API is not thread-safe:
+// - Start()/Stop() should only be called from the main (creation) thread.
+// - PostTask()/message_loop()/task_runner() are also safe to call from the
+// underlying thread itself (to post tasks from other threads: get the
+// task_runner() from the main thread first, it is then safe to pass _it_
+// around).
+class TestIOThread {
+ public:
+ enum Mode { kAutoStart, kManualStart };
+ explicit TestIOThread(Mode mode);
+ // Stops the I/O thread if necessary.
+ ~TestIOThread();
+
+ // After Stop(), Start() may be called again to start a new I/O thread.
+ // Stop() may be called even when the I/O thread is not started.
+ void Start();
+ void Stop();
+
+ // Post |task| to the IO thread.
+ void PostTask(const Location& from_here, base::OnceClosure task);
+
+ scoped_refptr<SingleThreadTaskRunner> task_runner() {
+ return io_thread_.task_runner();
+ }
+
+ private:
+ base::Thread io_thread_;
+ bool io_thread_started_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestIOThread);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_TEST_IO_THREAD_H_
diff --git a/chromium/base/test/test_listener_ios.h b/chromium/base/test/test_listener_ios.h
new file mode 100644
index 00000000000..c312250065d
--- /dev/null
+++ b/chromium/base/test/test_listener_ios.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_LISTENER_IOS_H_
+#define BASE_TEST_TEST_LISTENER_IOS_H_
+
+namespace base {
+namespace test_listener_ios {
+
+// Register an IOSRunLoopListener.
+void RegisterTestEndListener();
+
+} // namespace test_listener_ios
+} // namespace base
+
+#endif // BASE_TEST_TEST_LISTENER_IOS_H_
diff --git a/chromium/base/test/test_listener_ios.mm b/chromium/base/test/test_listener_ios.mm
new file mode 100644
index 00000000000..54aa9acb6d0
--- /dev/null
+++ b/chromium/base/test/test_listener_ios.mm
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_listener_ios.h"
+
+#import <Foundation/Foundation.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// The iOS watchdog timer will kill an app that doesn't spin the main event
+// loop often enough. This uses a Gtest TestEventListener to spin the current
+// loop after each test finishes. However, if any individual test takes too
+// long, it is still possible that the app will get killed.
+
+namespace {
+
+class IOSRunLoopListener : public testing::EmptyTestEventListener {
+ public:
+ virtual void OnTestEnd(const testing::TestInfo& test_info);
+};
+
+void IOSRunLoopListener::OnTestEnd(const testing::TestInfo& test_info) {
+ @autoreleasepool {
+ // At the end of the test, spin the default loop for a moment.
+ NSDate* stop_date = [NSDate dateWithTimeIntervalSinceNow:0.001];
+ [[NSRunLoop currentRunLoop] runUntilDate:stop_date];
+ }
+}
+
+} // namespace
+
+
+namespace base {
+namespace test_listener_ios {
+
+void RegisterTestEndListener() {
+ testing::TestEventListeners& listeners =
+ testing::UnitTest::GetInstance()->listeners();
+ listeners.Append(new IOSRunLoopListener);
+}
+
+} // namespace test_listener_ios
+} // namespace base
diff --git a/chromium/base/test/test_message_loop.cc b/chromium/base/test/test_message_loop.cc
new file mode 100644
index 00000000000..14f60b0ca02
--- /dev/null
+++ b/chromium/base/test/test_message_loop.cc
@@ -0,0 +1,50 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_message_loop.h"
+
+#include "base/compiler_specific.h"
+#include "base/message_loop/message_pump_type.h"
+#include "base/notreached.h"
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace {
+
+test::SingleThreadTaskEnvironment::MainThreadType GetMainThreadType(
+ MessagePumpType type) {
+ switch (type) {
+ case MessagePumpType::DEFAULT:
+ return test::SingleThreadTaskEnvironment::MainThreadType::DEFAULT;
+ case MessagePumpType::IO:
+ return test::SingleThreadTaskEnvironment::MainThreadType::IO;
+ case MessagePumpType::UI:
+ return test::SingleThreadTaskEnvironment::MainThreadType::UI;
+ case MessagePumpType::CUSTOM:
+#if defined(OS_ANDROID)
+ case MessagePumpType::JAVA:
+#elif defined(OS_MACOSX)
+ case MessagePumpType::NS_RUNLOOP:
+#elif defined(OS_WIN)
+ case MessagePumpType::UI_WITH_WM_QUIT_SUPPORT:
+#endif
+ NOTREACHED();
+ return test::SingleThreadTaskEnvironment::MainThreadType::DEFAULT;
+ }
+}
+} // namespace
+
+TestMessageLoop::TestMessageLoop() = default;
+
+TestMessageLoop::TestMessageLoop(MessagePumpType type)
+ : task_environment_(GetMainThreadType(type)) {}
+
+TestMessageLoop::~TestMessageLoop() {
+ RunLoop().RunUntilIdle();
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_message_loop.h b/chromium/base/test/test_message_loop.h
new file mode 100644
index 00000000000..3be2ea5c7a2
--- /dev/null
+++ b/chromium/base/test/test_message_loop.h
@@ -0,0 +1,39 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_MESSAGE_LOOP_H_
+#define BASE_TEST_TEST_MESSAGE_LOOP_H_
+
+#include "base/message_loop/message_pump_type.h"
+#include "base/single_thread_task_runner.h"
+#include "base/test/task_environment.h"
+
+namespace base {
+
+// TestMessageLoop is a convenience class for unittests that need to create a
+// message loop without a real thread backing it. For most tests,
+// it is sufficient to just instantiate TestMessageLoop as a member variable.
+//
+// TestMessageLoop will attempt to drain the underlying MessageLoop on
+// destruction for clean teardown of tests.
+//
+// TODO(b/891670): Get rid of this and migrate users to
+// SingleThreadTaskEnvironment
+class TestMessageLoop {
+ public:
+ TestMessageLoop();
+ explicit TestMessageLoop(MessagePumpType type);
+ ~TestMessageLoop();
+
+ scoped_refptr<SingleThreadTaskRunner> task_runner() {
+ return task_environment_.GetMainThreadTaskRunner();
+ }
+
+ private:
+ test::SingleThreadTaskEnvironment task_environment_;
+};
+
+} // namespace base
+
+#endif // BASE_TEST_TEST_MESSAGE_LOOP_H_
diff --git a/chromium/base/test/test_mock_time_task_runner.cc b/chromium/base/test/test_mock_time_task_runner.cc
new file mode 100644
index 00000000000..63aacf948d5
--- /dev/null
+++ b/chromium/base/test/test_mock_time_task_runner.cc
@@ -0,0 +1,501 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_mock_time_task_runner.h"
+
+#include <utility>
+
+#include "base/check_op.h"
+#include "base/containers/circular_deque.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace base {
+namespace {
+
+// LegacyMockTickClock and LegacyMockClock are used by deprecated APIs of
+// TestMockTimeTaskRunner. They will be removed after updating callers of
+// GetMockClock() and GetMockTickClock() to GetMockClockPtr() and
+// GetMockTickClockPtr().
+class LegacyMockTickClock : public TickClock {
+ public:
+ explicit LegacyMockTickClock(
+ scoped_refptr<const TestMockTimeTaskRunner> task_runner)
+ : task_runner_(std::move(task_runner)) {}
+
+ // TickClock:
+ TimeTicks NowTicks() const override { return task_runner_->NowTicks(); }
+
+ private:
+ scoped_refptr<const TestMockTimeTaskRunner> task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(LegacyMockTickClock);
+};
+
+class LegacyMockClock : public Clock {
+ public:
+ explicit LegacyMockClock(
+ scoped_refptr<const TestMockTimeTaskRunner> task_runner)
+ : task_runner_(std::move(task_runner)) {}
+
+ // Clock:
+ Time Now() const override { return task_runner_->Now(); }
+
+ private:
+ scoped_refptr<const TestMockTimeTaskRunner> task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(LegacyMockClock);
+};
+
+} // namespace
+
+// A SingleThreadTaskRunner which forwards everything to its |target_|. This
+// serves two purposes:
+// 1) If a ThreadTaskRunnerHandle owned by TestMockTimeTaskRunner were to be
+// set to point to that TestMockTimeTaskRunner, a reference cycle would
+// result. As |target_| here is a non-refcounting raw pointer, the cycle is
+// broken.
+// 2) Since SingleThreadTaskRunner is ref-counted, it's quite easy for it to
+// accidentally get captured between tests in a singleton somewhere.
+// Indirecting via NonOwningProxyTaskRunner permits TestMockTimeTaskRunner
+// to be cleaned up (removing the RunLoop::Delegate in the kBoundToThread
+// mode), and to also cleanly flag any actual attempts to use the leaked
+// task runner.
+class TestMockTimeTaskRunner::NonOwningProxyTaskRunner
+ : public SingleThreadTaskRunner {
+ public:
+ explicit NonOwningProxyTaskRunner(SingleThreadTaskRunner* target)
+ : target_(target) {
+ DCHECK(target_);
+ }
+
+ // Detaches this NonOwningProxyTaskRunner instance from its |target_|. It is
+ // invalid to post tasks after this point but RunsTasksInCurrentSequence()
+ // will still pass on the original thread for convenience with legacy code.
+ void Detach() {
+ AutoLock scoped_lock(lock_);
+ target_ = nullptr;
+ }
+
+ // SingleThreadTaskRunner:
+ bool RunsTasksInCurrentSequence() const override {
+ AutoLock scoped_lock(lock_);
+ if (target_)
+ return target_->RunsTasksInCurrentSequence();
+ return thread_checker_.CalledOnValidThread();
+ }
+
+ bool PostDelayedTask(const Location& from_here,
+ OnceClosure task,
+ TimeDelta delay) override {
+ AutoLock scoped_lock(lock_);
+ if (target_)
+ return target_->PostDelayedTask(from_here, std::move(task), delay);
+
+ // The associated TestMockTimeTaskRunner is dead, so fail this PostTask.
+ return false;
+ }
+
+ bool PostNonNestableDelayedTask(const Location& from_here,
+ OnceClosure task,
+ TimeDelta delay) override {
+ AutoLock scoped_lock(lock_);
+ if (target_) {
+ return target_->PostNonNestableDelayedTask(from_here, std::move(task),
+ delay);
+ }
+
+ // The associated TestMockTimeTaskRunner is dead, so fail this PostTask.
+ return false;
+ }
+
+ private:
+ friend class RefCountedThreadSafe<NonOwningProxyTaskRunner>;
+ ~NonOwningProxyTaskRunner() override = default;
+
+ mutable Lock lock_;
+ SingleThreadTaskRunner* target_; // guarded by lock_
+
+ // Used to implement RunsTasksInCurrentSequence, without relying on |target_|.
+ ThreadCheckerImpl thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(NonOwningProxyTaskRunner);
+};
+
+// TestMockTimeTaskRunner::TestOrderedPendingTask -----------------------------
+
+// Subclass of TestPendingTask which has a strictly monotonically increasing ID
+// for every task, so that tasks posted with the same 'time to run' can be run
+// in the order of being posted.
+struct TestMockTimeTaskRunner::TestOrderedPendingTask
+ : public base::TestPendingTask {
+ TestOrderedPendingTask();
+ TestOrderedPendingTask(const Location& location,
+ OnceClosure task,
+ TimeTicks post_time,
+ TimeDelta delay,
+ size_t ordinal,
+ TestNestability nestability);
+ TestOrderedPendingTask(TestOrderedPendingTask&&);
+ ~TestOrderedPendingTask();
+
+ TestOrderedPendingTask& operator=(TestOrderedPendingTask&&);
+
+ size_t ordinal;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestOrderedPendingTask);
+};
+
+TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask()
+ : ordinal(0) {
+}
+
+TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask(
+ TestOrderedPendingTask&&) = default;
+
+TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask(
+ const Location& location,
+ OnceClosure task,
+ TimeTicks post_time,
+ TimeDelta delay,
+ size_t ordinal,
+ TestNestability nestability)
+ : base::TestPendingTask(location,
+ std::move(task),
+ post_time,
+ delay,
+ nestability),
+ ordinal(ordinal) {}
+
+TestMockTimeTaskRunner::TestOrderedPendingTask::~TestOrderedPendingTask() =
+ default;
+
+TestMockTimeTaskRunner::TestOrderedPendingTask&
+TestMockTimeTaskRunner::TestOrderedPendingTask::operator=(
+ TestOrderedPendingTask&&) = default;
+
+// TestMockTimeTaskRunner -----------------------------------------------------
+
+// TODO(gab): This should also set the SequenceToken for the current thread.
+// Ref. TestMockTimeTaskRunner::RunsTasksInCurrentSequence().
+TestMockTimeTaskRunner::ScopedContext::ScopedContext(
+ scoped_refptr<TestMockTimeTaskRunner> scope)
+ : on_destroy_(ThreadTaskRunnerHandle::OverrideForTesting(scope)) {
+ scope->RunUntilIdle();
+}
+
+TestMockTimeTaskRunner::ScopedContext::~ScopedContext() = default;
+
+bool TestMockTimeTaskRunner::TemporalOrder::operator()(
+ const TestOrderedPendingTask& first_task,
+ const TestOrderedPendingTask& second_task) const {
+ if (first_task.GetTimeToRun() == second_task.GetTimeToRun())
+ return first_task.ordinal > second_task.ordinal;
+ return first_task.GetTimeToRun() > second_task.GetTimeToRun();
+}
+
+TestMockTimeTaskRunner::TestMockTimeTaskRunner(Type type)
+ : TestMockTimeTaskRunner(Time::UnixEpoch(), TimeTicks(), type) {}
+
+TestMockTimeTaskRunner::TestMockTimeTaskRunner(Time start_time,
+ TimeTicks start_ticks,
+ Type type)
+ : now_(start_time),
+ now_ticks_(start_ticks),
+ tasks_lock_cv_(&tasks_lock_),
+ proxy_task_runner_(MakeRefCounted<NonOwningProxyTaskRunner>(this)),
+ mock_clock_(this) {
+ if (type == Type::kBoundToThread) {
+ RunLoop::RegisterDelegateForCurrentThread(this);
+ thread_task_runner_handle_ =
+ std::make_unique<ThreadTaskRunnerHandle>(proxy_task_runner_);
+ }
+}
+
+TestMockTimeTaskRunner::~TestMockTimeTaskRunner() {
+ proxy_task_runner_->Detach();
+}
+
+void TestMockTimeTaskRunner::FastForwardBy(TimeDelta delta) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_GE(delta, TimeDelta());
+
+ const TimeTicks original_now_ticks = NowTicks();
+ ProcessAllTasksNoLaterThan(delta);
+ ForwardClocksUntilTickTime(original_now_ticks + delta);
+}
+
+void TestMockTimeTaskRunner::AdvanceMockTickClock(TimeDelta delta) {
+ ForwardClocksUntilTickTime(NowTicks() + delta);
+}
+
+void TestMockTimeTaskRunner::RunUntilIdle() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ ProcessAllTasksNoLaterThan(TimeDelta());
+}
+
+void TestMockTimeTaskRunner::FastForwardUntilNoTasksRemain() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ ProcessAllTasksNoLaterThan(TimeDelta::Max());
+}
+
+void TestMockTimeTaskRunner::ClearPendingTasks() {
+ AutoLock scoped_lock(tasks_lock_);
+ // This is repeated in case task destruction triggers further tasks.
+ while (!tasks_.empty()) {
+ TaskPriorityQueue cleanup_tasks;
+ tasks_.swap(cleanup_tasks);
+
+ // Destroy task objects with |tasks_lock_| released. Task deletion can cause
+ // calls to NonOwningProxyTaskRunner::RunsTasksInCurrentSequence()
+ // (e.g. for DCHECKs), which causes |NonOwningProxyTaskRunner::lock_| to be
+ // grabbed.
+ //
+ // On the other hand, calls from NonOwningProxyTaskRunner::PostTask ->
+ // TestMockTimeTaskRunner::PostTask acquire locks as
+ // |NonOwningProxyTaskRunner::lock_| followed by |tasks_lock_|, so it's
+ // desirable to avoid the reverse order, for deadlock freedom.
+ AutoUnlock scoped_unlock(tasks_lock_);
+ while (!cleanup_tasks.empty())
+ cleanup_tasks.pop();
+ }
+}
+
+Time TestMockTimeTaskRunner::Now() const {
+ AutoLock scoped_lock(tasks_lock_);
+ return now_;
+}
+
+TimeTicks TestMockTimeTaskRunner::NowTicks() const {
+ AutoLock scoped_lock(tasks_lock_);
+ return now_ticks_;
+}
+
+std::unique_ptr<Clock> TestMockTimeTaskRunner::DeprecatedGetMockClock() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return std::make_unique<LegacyMockClock>(this);
+}
+
+Clock* TestMockTimeTaskRunner::GetMockClock() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return &mock_clock_;
+}
+
+std::unique_ptr<TickClock> TestMockTimeTaskRunner::DeprecatedGetMockTickClock()
+ const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return std::make_unique<LegacyMockTickClock>(this);
+}
+
+const TickClock* TestMockTimeTaskRunner::GetMockTickClock() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return &mock_clock_;
+}
+
+base::circular_deque<TestPendingTask>
+TestMockTimeTaskRunner::TakePendingTasks() {
+ AutoLock scoped_lock(tasks_lock_);
+ base::circular_deque<TestPendingTask> tasks;
+ while (!tasks_.empty()) {
+ // It's safe to remove const and consume |task| here, since |task| is not
+ // used for ordering the item.
+ if (!tasks_.top().task.IsCancelled()) {
+ tasks.push_back(
+ std::move(const_cast<TestOrderedPendingTask&>(tasks_.top())));
+ }
+ tasks_.pop();
+ }
+ return tasks;
+}
+
+bool TestMockTimeTaskRunner::HasPendingTask() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ AutoLock scoped_lock(tasks_lock_);
+ while (!tasks_.empty() && tasks_.top().task.IsCancelled())
+ tasks_.pop();
+ return !tasks_.empty();
+}
+
+size_t TestMockTimeTaskRunner::GetPendingTaskCount() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ AutoLock scoped_lock(tasks_lock_);
+ TaskPriorityQueue preserved_tasks;
+ while (!tasks_.empty()) {
+ if (!tasks_.top().task.IsCancelled()) {
+ preserved_tasks.push(
+ std::move(const_cast<TestOrderedPendingTask&>(tasks_.top())));
+ }
+ tasks_.pop();
+ }
+ tasks_.swap(preserved_tasks);
+ return tasks_.size();
+}
+
+TimeDelta TestMockTimeTaskRunner::NextPendingTaskDelay() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ AutoLock scoped_lock(tasks_lock_);
+ while (!tasks_.empty() && tasks_.top().task.IsCancelled())
+ tasks_.pop();
+ return tasks_.empty() ? TimeDelta::Max()
+ : tasks_.top().GetTimeToRun() - now_ticks_;
+}
+
+// TODO(gab): Combine |thread_checker_| with a SequenceToken to differentiate
+// between tasks running in the scope of this TestMockTimeTaskRunner and other
+// task runners sharing this thread. http://crbug.com/631186
+bool TestMockTimeTaskRunner::RunsTasksInCurrentSequence() const {
+ return thread_checker_.CalledOnValidThread();
+}
+
+bool TestMockTimeTaskRunner::PostDelayedTask(const Location& from_here,
+ OnceClosure task,
+ TimeDelta delay) {
+ AutoLock scoped_lock(tasks_lock_);
+ tasks_.push(TestOrderedPendingTask(from_here, std::move(task), now_ticks_,
+ delay, next_task_ordinal_++,
+ TestPendingTask::NESTABLE));
+ tasks_lock_cv_.Signal();
+ return true;
+}
+
+bool TestMockTimeTaskRunner::PostNonNestableDelayedTask(
+ const Location& from_here,
+ OnceClosure task,
+ TimeDelta delay) {
+ return PostDelayedTask(from_here, std::move(task), delay);
+}
+
+void TestMockTimeTaskRunner::OnBeforeSelectingTask() {
+ // Empty default implementation.
+}
+
+void TestMockTimeTaskRunner::OnAfterTimePassed() {
+ // Empty default implementation.
+}
+
+void TestMockTimeTaskRunner::OnAfterTaskRun() {
+ // Empty default implementation.
+}
+
+void TestMockTimeTaskRunner::ProcessAllTasksNoLaterThan(TimeDelta max_delta) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_GE(max_delta, TimeDelta());
+
+ // Multiple test task runners can share the same thread for determinism in
+ // unit tests. Make sure this TestMockTimeTaskRunner's tasks run in its scope.
+ ScopedClosureRunner undo_override;
+ if (!ThreadTaskRunnerHandle::IsSet() ||
+ ThreadTaskRunnerHandle::Get() != proxy_task_runner_.get()) {
+ undo_override =
+ ThreadTaskRunnerHandle::OverrideForTesting(proxy_task_runner_.get());
+ }
+
+ const TimeTicks original_now_ticks = NowTicks();
+ while (!quit_run_loop_) {
+ OnBeforeSelectingTask();
+ TestPendingTask task_info;
+ if (!DequeueNextTask(original_now_ticks, max_delta, &task_info))
+ break;
+ if (task_info.task.IsCancelled())
+ continue;
+ // If tasks were posted with a negative delay, task_info.GetTimeToRun() will
+ // be less than |now_ticks_|. ForwardClocksUntilTickTime() takes care of not
+ // moving the clock backwards in this case.
+ ForwardClocksUntilTickTime(task_info.GetTimeToRun());
+ std::move(task_info.task).Run();
+ OnAfterTaskRun();
+ }
+}
+
+void TestMockTimeTaskRunner::ForwardClocksUntilTickTime(TimeTicks later_ticks) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ {
+ AutoLock scoped_lock(tasks_lock_);
+ if (later_ticks <= now_ticks_)
+ return;
+
+ now_ += later_ticks - now_ticks_;
+ now_ticks_ = later_ticks;
+ }
+ OnAfterTimePassed();
+}
+
+bool TestMockTimeTaskRunner::DequeueNextTask(const TimeTicks& reference,
+ const TimeDelta& max_delta,
+ TestPendingTask* next_task) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ AutoLock scoped_lock(tasks_lock_);
+ if (!tasks_.empty() &&
+ (tasks_.top().GetTimeToRun() - reference) <= max_delta) {
+ // It's safe to remove const and consume |task| here, since |task| is not
+ // used for ordering the item.
+ *next_task = std::move(const_cast<TestOrderedPendingTask&>(tasks_.top()));
+ tasks_.pop();
+ return true;
+ }
+ return false;
+}
+
+void TestMockTimeTaskRunner::Run(bool application_tasks_allowed,
+ TimeDelta timeout) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Since TestMockTimeTaskRunner doesn't process system messages: there's no
+ // hope for anything but an application task to call Quit(). If this RunLoop
+ // can't process application tasks (i.e. disallowed by default in nested
+ // RunLoops) it's guaranteed to hang...
+ DCHECK(application_tasks_allowed)
+ << "This is a nested RunLoop instance and needs to be of "
+ "Type::kNestableTasksAllowed.";
+
+ // This computation relies on saturated arithmetic.
+ TimeTicks run_until = now_ticks_ + timeout;
+ while (!quit_run_loop_ && now_ticks_ < run_until) {
+ RunUntilIdle();
+ if (quit_run_loop_ || ShouldQuitWhenIdle())
+ break;
+
+ // Peek into |tasks_| to perform one of two things:
+ // A) If there are no remaining tasks, wait until one is posted and
+ // restart from the top.
+ // B) If there is a remaining delayed task. Fast-forward to reach the next
+ // round of tasks.
+ TimeDelta auto_fast_forward_by;
+ {
+ AutoLock scoped_lock(tasks_lock_);
+ if (tasks_.empty()) {
+ while (tasks_.empty())
+ tasks_lock_cv_.Wait();
+ continue;
+ }
+ auto_fast_forward_by =
+ std::min(run_until, tasks_.top().GetTimeToRun()) - now_ticks_;
+ }
+ FastForwardBy(auto_fast_forward_by);
+ }
+ quit_run_loop_ = false;
+}
+
+void TestMockTimeTaskRunner::Quit() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ quit_run_loop_ = true;
+}
+
+void TestMockTimeTaskRunner::EnsureWorkScheduled() {
+ // Nothing to do: TestMockTimeTaskRunner::Run() will always process tasks and
+ // doesn't need an extra kick on nested runs.
+}
+
+TimeTicks TestMockTimeTaskRunner::MockClock::NowTicks() const {
+ return task_runner_->NowTicks();
+}
+
+Time TestMockTimeTaskRunner::MockClock::Now() const {
+ return task_runner_->Now();
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_mock_time_task_runner_unittest.cc b/chromium/base/test/test_mock_time_task_runner_unittest.cc
new file mode 100644
index 00000000000..80805298ada
--- /dev/null
+++ b/chromium/base/test/test_mock_time_task_runner_unittest.cc
@@ -0,0 +1,298 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_mock_time_task_runner.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/cancelable_callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/gtest_util.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Basic usage should work the same from default and bound
+// TestMockTimeTaskRunners.
+TEST(TestMockTimeTaskRunnerTest, Basic) {
+ static constexpr TestMockTimeTaskRunner::Type kTestCases[] = {
+ TestMockTimeTaskRunner::Type::kStandalone,
+ TestMockTimeTaskRunner::Type::kBoundToThread};
+
+ for (auto type : kTestCases) {
+ SCOPED_TRACE(static_cast<int>(type));
+
+ auto mock_time_task_runner = MakeRefCounted<TestMockTimeTaskRunner>(type);
+ int counter = 0;
+
+ mock_time_task_runner->PostTask(
+ FROM_HERE, base::BindOnce([](int* counter) { *counter += 1; },
+ Unretained(&counter)));
+ mock_time_task_runner->PostTask(
+ FROM_HERE, base::BindOnce([](int* counter) { *counter += 32; },
+ Unretained(&counter)));
+ mock_time_task_runner->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 256; },
+ Unretained(&counter)),
+ TimeDelta::FromSeconds(3));
+ mock_time_task_runner->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 64; },
+ Unretained(&counter)),
+ TimeDelta::FromSeconds(1));
+ mock_time_task_runner->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 1024; },
+ Unretained(&counter)),
+ TimeDelta::FromMinutes(20));
+ mock_time_task_runner->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 4096; },
+ Unretained(&counter)),
+ TimeDelta::FromDays(20));
+
+ int expected_value = 0;
+ EXPECT_EQ(expected_value, counter);
+ mock_time_task_runner->RunUntilIdle();
+ expected_value += 1;
+ expected_value += 32;
+ EXPECT_EQ(expected_value, counter);
+
+ mock_time_task_runner->RunUntilIdle();
+ EXPECT_EQ(expected_value, counter);
+
+ mock_time_task_runner->FastForwardBy(TimeDelta::FromSeconds(1));
+ expected_value += 64;
+ EXPECT_EQ(expected_value, counter);
+
+ mock_time_task_runner->FastForwardBy(TimeDelta::FromSeconds(5));
+ expected_value += 256;
+ EXPECT_EQ(expected_value, counter);
+
+ mock_time_task_runner->FastForwardUntilNoTasksRemain();
+ expected_value += 1024;
+ expected_value += 4096;
+ EXPECT_EQ(expected_value, counter);
+ }
+}
+
+// A default TestMockTimeTaskRunner shouldn't result in a thread association.
+TEST(TestMockTimeTaskRunnerTest, DefaultUnbound) {
+ auto unbound_mock_time_task_runner = MakeRefCounted<TestMockTimeTaskRunner>();
+ EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet());
+ EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet());
+ EXPECT_DEATH_IF_SUPPORTED({ RunLoop().RunUntilIdle(); }, "");
+}
+
+TEST(TestMockTimeTaskRunnerTest, RunLoopDriveableWhenBound) {
+ auto bound_mock_time_task_runner = MakeRefCounted<TestMockTimeTaskRunner>(
+ TestMockTimeTaskRunner::Type::kBoundToThread);
+
+ int counter = 0;
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce([](int* counter) { *counter += 1; },
+ Unretained(&counter)));
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce([](int* counter) { *counter += 32; },
+ Unretained(&counter)));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 256; },
+ Unretained(&counter)),
+ TimeDelta::FromSeconds(3));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 64; },
+ Unretained(&counter)),
+ TimeDelta::FromSeconds(1));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 1024; },
+ Unretained(&counter)),
+ TimeDelta::FromMinutes(20));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 4096; },
+ Unretained(&counter)),
+ TimeDelta::FromDays(20));
+
+ int expected_value = 0;
+ EXPECT_EQ(expected_value, counter);
+ RunLoop().RunUntilIdle();
+ expected_value += 1;
+ expected_value += 32;
+ EXPECT_EQ(expected_value, counter);
+
+ RunLoop().RunUntilIdle();
+ EXPECT_EQ(expected_value, counter);
+
+ {
+ RunLoop run_loop;
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(), TimeDelta::FromSeconds(1));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 8192; },
+ Unretained(&counter)),
+ TimeDelta::FromSeconds(1));
+
+ // The QuitClosure() should be ordered between the 64 and the 8192
+ // increments and should preempt the latter.
+ run_loop.Run();
+ expected_value += 64;
+ EXPECT_EQ(expected_value, counter);
+
+ // Running until idle should process the 8192 increment whose delay has
+ // expired in the previous Run().
+ RunLoop().RunUntilIdle();
+ expected_value += 8192;
+ EXPECT_EQ(expected_value, counter);
+ }
+
+ {
+ RunLoop run_loop;
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitWhenIdleClosure(), TimeDelta::FromSeconds(5));
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce([](int* counter) { *counter += 16384; },
+ Unretained(&counter)),
+ TimeDelta::FromSeconds(5));
+
+ // The QuitWhenIdleClosure() shouldn't preempt equally delayed tasks and as
+ // such the 16384 increment should be processed before quitting.
+ run_loop.Run();
+ expected_value += 256;
+ expected_value += 16384;
+ EXPECT_EQ(expected_value, counter);
+ }
+
+ // Process the remaining tasks (note: do not mimic this elsewhere,
+ // TestMockTimeTaskRunner::FastForwardUntilNoTasksRemain() is a better API to
+ // do this, this is just done here for the purpose of extensively testing the
+ // RunLoop approach).
+ RunLoop run_loop;
+ ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitWhenIdleClosure(), TimeDelta::FromDays(50));
+
+ run_loop.Run();
+ expected_value += 1024;
+ expected_value += 4096;
+ EXPECT_EQ(expected_value, counter);
+}
+
+TEST(TestMockTimeTaskRunnerTest, AvoidCaptureWhenBound) {
+ // Make sure that capturing the active task runner --- which sometimes happens
+ // unknowingly due to ThreadsafeObserverList deep within some singleton ---
+ // does not keep the entire TestMockTimeTaskRunner alive, as in bound mode
+ // that's a RunLoop::Delegate, and leaking that renders any further tests that
+ // need RunLoop support unrunnable.
+ //
+ // (This used to happen when code run from ProcessAllTasksNoLaterThan grabbed
+ // the runner.).
+ scoped_refptr<SingleThreadTaskRunner> captured;
+ {
+ auto task_runner = MakeRefCounted<TestMockTimeTaskRunner>(
+ TestMockTimeTaskRunner::Type::kBoundToThread);
+
+ task_runner->PostTask(FROM_HERE, base::BindLambdaForTesting([&]() {
+ captured = ThreadTaskRunnerHandle::Get();
+ }));
+ task_runner->RunUntilIdle();
+ }
+
+ {
+ // This should not complain about RunLoop::Delegate already existing.
+ auto task_runner2 = MakeRefCounted<TestMockTimeTaskRunner>(
+ TestMockTimeTaskRunner::Type::kBoundToThread);
+ }
+}
+
+// Regression test that receiving the quit-when-idle signal when already empty
+// works as intended (i.e. that |TestMockTimeTaskRunner::tasks_lock_cv| is
+// properly signaled).
+TEST(TestMockTimeTaskRunnerTest, RunLoopQuitFromIdle) {
+ auto bound_mock_time_task_runner = MakeRefCounted<TestMockTimeTaskRunner>(
+ TestMockTimeTaskRunner::Type::kBoundToThread);
+
+ Thread quitting_thread("quitting thread");
+ quitting_thread.Start();
+
+ RunLoop run_loop;
+ quitting_thread.task_runner()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitWhenIdleClosure(), TestTimeouts::tiny_timeout());
+ run_loop.Run();
+}
+
+TEST(TestMockTimeTaskRunnerTest, TakePendingTasks) {
+ auto task_runner = MakeRefCounted<TestMockTimeTaskRunner>();
+ task_runner->PostTask(FROM_HERE, DoNothing());
+ EXPECT_TRUE(task_runner->HasPendingTask());
+ EXPECT_EQ(1u, task_runner->TakePendingTasks().size());
+ EXPECT_FALSE(task_runner->HasPendingTask());
+}
+
+TEST(TestMockTimeTaskRunnerTest, CancelPendingTask) {
+ auto task_runner = MakeRefCounted<TestMockTimeTaskRunner>();
+ CancelableOnceClosure task1(DoNothing::Once());
+ task_runner->PostDelayedTask(FROM_HERE, task1.callback(),
+ TimeDelta::FromSeconds(1));
+ EXPECT_TRUE(task_runner->HasPendingTask());
+ EXPECT_EQ(1u, task_runner->GetPendingTaskCount());
+ EXPECT_EQ(TimeDelta::FromSeconds(1), task_runner->NextPendingTaskDelay());
+ task1.Cancel();
+ EXPECT_FALSE(task_runner->HasPendingTask());
+
+ CancelableOnceClosure task2(DoNothing::Once());
+ task_runner->PostDelayedTask(FROM_HERE, task2.callback(),
+ TimeDelta::FromSeconds(1));
+ task2.Cancel();
+ EXPECT_EQ(0u, task_runner->GetPendingTaskCount());
+
+ CancelableOnceClosure task3(DoNothing::Once());
+ task_runner->PostDelayedTask(FROM_HERE, task3.callback(),
+ TimeDelta::FromSeconds(1));
+ task3.Cancel();
+ EXPECT_EQ(TimeDelta::Max(), task_runner->NextPendingTaskDelay());
+
+ CancelableOnceClosure task4(DoNothing::Once());
+ task_runner->PostDelayedTask(FROM_HERE, task4.callback(),
+ TimeDelta::FromSeconds(1));
+ task4.Cancel();
+ EXPECT_TRUE(task_runner->TakePendingTasks().empty());
+}
+
+TEST(TestMockTimeTaskRunnerTest, NoFastForwardToCancelledTask) {
+ auto task_runner = MakeRefCounted<TestMockTimeTaskRunner>();
+ TimeTicks start_time = task_runner->NowTicks();
+ CancelableOnceClosure task(DoNothing::Once());
+ task_runner->PostDelayedTask(FROM_HERE, task.callback(),
+ TimeDelta::FromSeconds(1));
+ EXPECT_EQ(TimeDelta::FromSeconds(1), task_runner->NextPendingTaskDelay());
+ task.Cancel();
+ task_runner->FastForwardUntilNoTasksRemain();
+ EXPECT_EQ(start_time, task_runner->NowTicks());
+}
+
+TEST(TestMockTimeTaskRunnerTest, AdvanceMockTickClockDoesNotRunTasks) {
+ auto task_runner = MakeRefCounted<TestMockTimeTaskRunner>();
+ TimeTicks start_time = task_runner->NowTicks();
+ task_runner->PostTask(FROM_HERE, BindOnce([]() { ADD_FAILURE(); }));
+ task_runner->PostDelayedTask(FROM_HERE, BindOnce([]() { ADD_FAILURE(); }),
+ TimeDelta::FromSeconds(1));
+
+ task_runner->AdvanceMockTickClock(TimeDelta::FromSeconds(3));
+ EXPECT_EQ(start_time + TimeDelta::FromSeconds(3), task_runner->NowTicks());
+ EXPECT_EQ(2u, task_runner->GetPendingTaskCount());
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_reg_util_win.cc b/chromium/base/test/test_reg_util_win.cc
new file mode 100644
index 00000000000..6bcfe60bfeb
--- /dev/null
+++ b/chromium/base/test/test_reg_util_win.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_reg_util_win.h"
+
+#include <stdint.h>
+
+#include "base/guid.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include <windows.h>
+
+namespace registry_util {
+
+namespace {
+
+constexpr base::char16 kTimestampDelimiter[] = STRING16_LITERAL("$");
+constexpr wchar_t kTempTestKeyPath[] = L"Software\\Chromium\\TempTestKeys";
+
+void DeleteStaleTestKeys(const base::Time& now,
+ const std::wstring& test_key_root) {
+ base::win::RegKey test_root_key;
+ if (test_root_key.Open(HKEY_CURRENT_USER,
+ test_key_root.c_str(),
+ KEY_ALL_ACCESS) != ERROR_SUCCESS) {
+ // This will occur on first-run, but is harmless.
+ return;
+ }
+
+ base::win::RegistryKeyIterator iterator_test_root_key(HKEY_CURRENT_USER,
+ test_key_root.c_str());
+ for (; iterator_test_root_key.Valid(); ++iterator_test_root_key) {
+ std::wstring key_name = iterator_test_root_key.Name();
+ std::vector<base::StringPiece16> tokens = base::SplitStringPiece(
+ base::AsStringPiece16(key_name), kTimestampDelimiter,
+ base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ if (tokens.empty())
+ continue;
+ int64_t key_name_as_number = 0;
+
+ if (!base::StringToInt64(tokens[0], &key_name_as_number)) {
+ test_root_key.DeleteKey(key_name.c_str());
+ continue;
+ }
+
+ base::Time key_time = base::Time::FromInternalValue(key_name_as_number);
+ base::TimeDelta age = now - key_time;
+
+ if (age > base::TimeDelta::FromHours(24))
+ test_root_key.DeleteKey(key_name.c_str());
+ }
+}
+
+std::wstring GenerateTempKeyPath(const std::wstring& test_key_root,
+ const base::Time& timestamp) {
+ return base::AsWString(base::StrCat(
+ {base::AsStringPiece16(test_key_root), STRING16_LITERAL("\\"),
+ base::NumberToString16(timestamp.ToInternalValue()), kTimestampDelimiter,
+ base::ASCIIToUTF16(base::GenerateGUID())}));
+}
+
+} // namespace
+
+RegistryOverrideManager::ScopedRegistryKeyOverride::ScopedRegistryKeyOverride(
+ HKEY override,
+ const std::wstring& key_path)
+ : override_(override), key_path_(key_path) {}
+
+RegistryOverrideManager::
+ ScopedRegistryKeyOverride::~ScopedRegistryKeyOverride() {
+ ::RegOverridePredefKey(override_, NULL);
+ base::win::RegKey(HKEY_CURRENT_USER, L"", KEY_QUERY_VALUE)
+ .DeleteKey(key_path_.c_str());
+}
+
+RegistryOverrideManager::RegistryOverrideManager()
+ : timestamp_(base::Time::Now()), test_key_root_(kTempTestKeyPath) {
+ DeleteStaleTestKeys(timestamp_, test_key_root_);
+}
+
+RegistryOverrideManager::RegistryOverrideManager(
+ const base::Time& timestamp,
+ const std::wstring& test_key_root)
+ : timestamp_(timestamp), test_key_root_(test_key_root) {
+ DeleteStaleTestKeys(timestamp_, test_key_root_);
+}
+
+RegistryOverrideManager::~RegistryOverrideManager() {}
+
+void RegistryOverrideManager::OverrideRegistry(HKEY override) {
+ OverrideRegistry(override, nullptr);
+}
+
+void RegistryOverrideManager::OverrideRegistry(HKEY override,
+ std::wstring* override_path) {
+ std::wstring key_path = GenerateTempKeyPath(test_key_root_, timestamp_);
+
+ base::win::RegKey temp_key;
+ ASSERT_EQ(ERROR_SUCCESS, temp_key.Create(HKEY_CURRENT_USER, key_path.c_str(),
+ KEY_ALL_ACCESS));
+ ASSERT_EQ(ERROR_SUCCESS, ::RegOverridePredefKey(override, temp_key.Handle()));
+
+ overrides_.push_back(
+ std::make_unique<ScopedRegistryKeyOverride>(override, key_path));
+ if (override_path)
+ override_path->assign(key_path);
+}
+
+std::wstring GenerateTempKeyPath() {
+ return GenerateTempKeyPath(kTempTestKeyPath, base::Time::Now());
+}
+
+} // namespace registry_util
diff --git a/chromium/base/test/test_reg_util_win.h b/chromium/base/test/test_reg_util_win.h
new file mode 100644
index 00000000000..0592ff7176c
--- /dev/null
+++ b/chromium/base/test/test_reg_util_win.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_REG_UTIL_WIN_H_
+#define BASE_TEST_TEST_REG_UTIL_WIN_H_
+
+// Registry utility functions used only by tests.
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "base/win/registry.h"
+
+namespace registry_util {
+
+// Allows a test to easily override registry hives so that it can start from a
+// known good state, or make sure to not leave any side effects once the test
+// completes. This supports parallel tests. All the overrides are scoped to the
+// lifetime of the override manager. Destroy the manager to undo the overrides.
+//
+// Overridden hives use keys stored at, for instance:
+// HKCU\Software\Chromium\TempTestKeys\
+// 13028145911617809$02AB211C-CF73-478D-8D91-618E11998AED
+// The key path are comprises of:
+// - The test key root, HKCU\Software\Chromium\TempTestKeys\
+// - The base::Time::ToInternalValue of the creation time. This is used to
+// delete stale keys left over from crashed tests.
+// - A GUID used for preventing name collisions (although unlikely) between
+// two RegistryOverrideManagers created with the same timestamp.
+class RegistryOverrideManager {
+ public:
+ RegistryOverrideManager();
+ ~RegistryOverrideManager();
+
+ // Override the given registry hive using a randomly generated temporary key.
+ // Multiple overrides to the same hive are not supported and lead to undefined
+ // behavior.
+ // Optional return of the registry override path.
+ // Calls to these functions must be wrapped in ASSERT_NO_FATAL_FAILURE to
+ // ensure that tests do not proceeed in case of failure to override.
+ void OverrideRegistry(HKEY override);
+ void OverrideRegistry(HKEY override, std::wstring* override_path);
+
+ private:
+ friend class RegistryOverrideManagerTest;
+
+ // Keeps track of one override.
+ class ScopedRegistryKeyOverride {
+ public:
+ ScopedRegistryKeyOverride(HKEY override, const std::wstring& key_path);
+ ~ScopedRegistryKeyOverride();
+
+ private:
+ HKEY override_;
+ std::wstring key_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedRegistryKeyOverride);
+ };
+
+ // Used for testing only.
+ RegistryOverrideManager(const base::Time& timestamp,
+ const std::wstring& test_key_root);
+
+ base::Time timestamp_;
+ std::wstring guid_;
+
+ std::wstring test_key_root_;
+ std::vector<std::unique_ptr<ScopedRegistryKeyOverride>> overrides_;
+
+ DISALLOW_COPY_AND_ASSIGN(RegistryOverrideManager);
+};
+
+// Generates a temporary key path that will be eventually deleted
+// automatically if the process crashes.
+std::wstring GenerateTempKeyPath();
+
+} // namespace registry_util
+
+#endif // BASE_TEST_TEST_REG_UTIL_WIN_H_
diff --git a/chromium/base/test/test_reg_util_win_unittest.cc b/chromium/base/test/test_reg_util_win_unittest.cc
new file mode 100644
index 00000000000..12c1d6b9970
--- /dev/null
+++ b/chromium/base/test/test_reg_util_win_unittest.cc
@@ -0,0 +1,134 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_reg_util_win.h"
+
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace registry_util {
+
+namespace {
+const wchar_t kTestKeyPath[] = L"Software\\Chromium\\Foo\\Baz\\TestKey";
+const wchar_t kTestValueName[] = L"TestValue";
+} // namespace
+
+class RegistryOverrideManagerTest : public testing::Test {
+ protected:
+ RegistryOverrideManagerTest() {
+ // We assign a fake test key path to our test RegistryOverrideManager
+ // so we don't interfere with any actual RegistryOverrideManagers running
+ // on the system. This fake path will be auto-deleted by other
+ // RegistryOverrideManagers in case we crash.
+ fake_test_key_root_ = registry_util::GenerateTempKeyPath();
+
+ // Ensure a clean test environment.
+ base::win::RegKey key(HKEY_CURRENT_USER);
+ key.DeleteKey(fake_test_key_root_.c_str());
+ key.DeleteKey(kTestKeyPath);
+ }
+
+ ~RegistryOverrideManagerTest() override {
+ base::win::RegKey key(HKEY_CURRENT_USER);
+ key.DeleteKey(fake_test_key_root_.c_str());
+ }
+
+ void AssertKeyExists(const std::wstring& key_path) {
+ base::win::RegKey key;
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ))
+ << key_path << " does not exist.";
+ }
+
+ void AssertKeyAbsent(const std::wstring& key_path) {
+ base::win::RegKey key;
+ ASSERT_NE(ERROR_SUCCESS,
+ key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ))
+ << key_path << " exists but it should not.";
+ }
+
+ void CreateKey(const std::wstring& key_path) {
+ base::win::RegKey key;
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_ALL_ACCESS));
+ }
+
+ std::wstring FakeOverrideManagerPath(const base::Time& time) {
+ return fake_test_key_root_ + L"\\" +
+ base::AsWString(base::NumberToString16(time.ToInternalValue()));
+ }
+
+ void CreateManager(const base::Time& timestamp) {
+ manager_.reset(new RegistryOverrideManager(timestamp, fake_test_key_root_));
+ manager_->OverrideRegistry(HKEY_CURRENT_USER);
+ }
+
+ std::wstring fake_test_key_root_;
+ std::unique_ptr<RegistryOverrideManager> manager_;
+};
+
+TEST_F(RegistryOverrideManagerTest, Basic) {
+ ASSERT_NO_FATAL_FAILURE(CreateManager(base::Time::Now()));
+
+ base::win::RegKey create_key;
+ EXPECT_EQ(ERROR_SUCCESS,
+ create_key.Create(HKEY_CURRENT_USER, kTestKeyPath, KEY_ALL_ACCESS));
+ EXPECT_TRUE(create_key.Valid());
+ EXPECT_EQ(ERROR_SUCCESS, create_key.WriteValue(kTestValueName, 42));
+ create_key.Close();
+
+ ASSERT_NO_FATAL_FAILURE(AssertKeyExists(kTestKeyPath));
+
+ DWORD value;
+ base::win::RegKey read_key;
+ EXPECT_EQ(ERROR_SUCCESS,
+ read_key.Open(HKEY_CURRENT_USER, kTestKeyPath, KEY_READ));
+ EXPECT_TRUE(read_key.Valid());
+ EXPECT_EQ(ERROR_SUCCESS, read_key.ReadValueDW(kTestValueName, &value));
+ EXPECT_EQ(42u, value);
+ read_key.Close();
+
+ manager_.reset();
+
+ ASSERT_NO_FATAL_FAILURE(AssertKeyAbsent(kTestKeyPath));
+}
+
+TEST_F(RegistryOverrideManagerTest, DeleteStaleKeys) {
+ base::Time::Exploded kTestTimeExploded = {2013, 11, 1, 4, 0, 0, 0, 0};
+ base::Time kTestTime;
+ EXPECT_TRUE(base::Time::FromUTCExploded(kTestTimeExploded, &kTestTime));
+
+ std::wstring path_garbage = fake_test_key_root_ + L"\\Blah";
+ std::wstring path_very_stale =
+ FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromDays(100));
+ std::wstring path_stale =
+ FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromDays(5));
+ std::wstring path_current =
+ FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromMinutes(1));
+ std::wstring path_future =
+ FakeOverrideManagerPath(kTestTime + base::TimeDelta::FromMinutes(1));
+
+ ASSERT_NO_FATAL_FAILURE(CreateKey(path_garbage));
+ ASSERT_NO_FATAL_FAILURE(CreateKey(path_very_stale));
+ ASSERT_NO_FATAL_FAILURE(CreateKey(path_stale));
+ ASSERT_NO_FATAL_FAILURE(CreateKey(path_current));
+ ASSERT_NO_FATAL_FAILURE(CreateKey(path_future));
+
+ ASSERT_NO_FATAL_FAILURE(CreateManager(kTestTime));
+ manager_.reset();
+
+ ASSERT_NO_FATAL_FAILURE(AssertKeyAbsent(path_garbage));
+ ASSERT_NO_FATAL_FAILURE(AssertKeyAbsent(path_very_stale));
+ ASSERT_NO_FATAL_FAILURE(AssertKeyAbsent(path_stale));
+ ASSERT_NO_FATAL_FAILURE(AssertKeyExists(path_current));
+ ASSERT_NO_FATAL_FAILURE(AssertKeyExists(path_future));
+}
+
+} // namespace registry_util
diff --git a/chromium/base/test/test_shared_library.cc b/chromium/base/test/test_shared_library.cc
new file mode 100644
index 00000000000..99c04674cea
--- /dev/null
+++ b/chromium/base/test/test_shared_library.cc
@@ -0,0 +1,30 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/native_library_test_utils.h"
+
+extern "C" {
+
+int NATIVE_LIBRARY_TEST_ALWAYS_EXPORT GetExportedValue() {
+ return g_native_library_exported_value;
+}
+
+void NATIVE_LIBRARY_TEST_ALWAYS_EXPORT SetExportedValue(int value) {
+ g_native_library_exported_value = value;
+}
+
+// A test function used only to verify basic dynamic symbol resolution.
+int NATIVE_LIBRARY_TEST_ALWAYS_EXPORT GetSimpleTestValue() {
+ return 5;
+}
+
+// When called by |NativeLibraryTest.LoadLibraryPreferOwnSymbols|, this should
+// forward to the local definition of NativeLibraryTestIncrement(), even though
+// the test module also links in the native_library_test_utils source library
+// which exports it.
+int NATIVE_LIBRARY_TEST_ALWAYS_EXPORT GetIncrementValue() {
+ return NativeLibraryTestIncrement();
+}
+
+} // extern "C"
diff --git a/chromium/base/test/test_shared_memory_util.cc b/chromium/base/test/test_shared_memory_util.cc
new file mode 100644
index 00000000000..43bbb7dbc2e
--- /dev/null
+++ b/chromium/base/test/test_shared_memory_util.cc
@@ -0,0 +1,169 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_shared_memory_util.h"
+
+#include <gtest/gtest.h>
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX) && !defined(OS_NACL)
+#include <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#endif
+
+#if defined(OS_FUCHSIA)
+#include <lib/zx/vmar.h>
+#include <zircon/rights.h>
+#endif
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include <mach/mach_vm.h>
+#endif
+
+#if defined(OS_WIN)
+#include <aclapi.h>
+#endif
+
+namespace base {
+
+#if !defined(OS_NACL)
+
+static const size_t kDataSize = 1024;
+
+// Common routine used with Posix file descriptors. Check that shared memory
+// file descriptor |fd| does not allow writable mappings. Return true on
+// success, false otherwise.
+#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+static bool CheckReadOnlySharedMemoryFdPosix(int fd) {
+// Note that the error on Android is EPERM, unlike other platforms where
+// it will be EACCES.
+#if defined(OS_ANDROID)
+ const int kExpectedErrno = EPERM;
+#else
+ const int kExpectedErrno = EACCES;
+#endif
+ errno = 0;
+ void* address =
+ mmap(nullptr, kDataSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ const bool success = (address != nullptr) && (address != MAP_FAILED);
+ if (success) {
+ LOG(ERROR) << "mmap() should have failed!";
+ munmap(address, kDataSize); // Cleanup.
+ return false;
+ }
+ if (errno != kExpectedErrno) {
+ LOG(ERROR) << "Expected mmap() to return " << kExpectedErrno
+ << " but returned " << errno << ": " << strerror(errno) << "\n";
+ return false;
+ }
+ return true;
+}
+#endif // OS_POSIX && !(defined(OS_MACOSX) && !defined(OS_IOS))
+
+#if defined(OS_FUCHSIA)
+// Fuchsia specific implementation.
+bool CheckReadOnlySharedMemoryFuchsiaHandle(zx::unowned_vmo handle) {
+ const uint32_t flags = ZX_VM_PERM_READ | ZX_VM_PERM_WRITE;
+ uintptr_t addr;
+ const zx_status_t status =
+ zx::vmar::root_self()->map(0, *handle, 0U, kDataSize, flags, &addr);
+ if (status == ZX_OK) {
+ LOG(ERROR) << "zx_vmar_map() should have failed!";
+ zx::vmar::root_self()->unmap(addr, kDataSize);
+ return false;
+ }
+ if (status != ZX_ERR_ACCESS_DENIED) {
+ LOG(ERROR) << "Expected zx_vmar_map() to return " << ZX_ERR_ACCESS_DENIED
+ << " (ZX_ERR_ACCESS_DENIED) but returned " << status << "\n";
+ return false;
+ }
+ return true;
+}
+
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+bool CheckReadOnlySharedMemoryMachPort(mach_port_t memory_object) {
+ mach_vm_address_t memory;
+ const kern_return_t kr = mach_vm_map(
+ mach_task_self(), &memory, kDataSize, 0, VM_FLAGS_ANYWHERE, memory_object,
+ 0, FALSE, VM_PROT_READ | VM_PROT_WRITE,
+ VM_PROT_READ | VM_PROT_WRITE | VM_PROT_IS_MASK, VM_INHERIT_NONE);
+ if (kr == KERN_SUCCESS) {
+ LOG(ERROR) << "mach_vm_map() should have failed!";
+ mach_vm_deallocate(mach_task_self(), memory, kDataSize); // Cleanup.
+ return false;
+ }
+ return true;
+}
+
+#elif defined(OS_WIN)
+bool CheckReadOnlySharedMemoryWindowsHandle(HANDLE handle) {
+ void* memory =
+ MapViewOfFile(handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kDataSize);
+ if (memory != nullptr) {
+ LOG(ERROR) << "MapViewOfFile() should have failed!";
+ UnmapViewOfFile(memory);
+ return false;
+ }
+ return true;
+}
+#endif
+
+bool CheckReadOnlyPlatformSharedMemoryRegionForTesting(
+ subtle::PlatformSharedMemoryRegion region) {
+ if (region.GetMode() != subtle::PlatformSharedMemoryRegion::Mode::kReadOnly) {
+ LOG(ERROR) << "Expected region mode is "
+ << static_cast<int>(
+ subtle::PlatformSharedMemoryRegion::Mode::kReadOnly)
+ << " but actual is " << static_cast<int>(region.GetMode());
+ return false;
+ }
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ return CheckReadOnlySharedMemoryMachPort(region.GetPlatformHandle());
+#elif defined(OS_FUCHSIA)
+ return CheckReadOnlySharedMemoryFuchsiaHandle(region.GetPlatformHandle());
+#elif defined(OS_WIN)
+ return CheckReadOnlySharedMemoryWindowsHandle(region.GetPlatformHandle());
+#elif defined(OS_ANDROID)
+ return CheckReadOnlySharedMemoryFdPosix(region.GetPlatformHandle());
+#else
+ return CheckReadOnlySharedMemoryFdPosix(region.GetPlatformHandle().fd);
+#endif
+}
+
+#endif // !OS_NACL
+
+WritableSharedMemoryMapping MapForTesting(
+ subtle::PlatformSharedMemoryRegion* region) {
+ return MapAtForTesting(region, 0, region->GetSize());
+}
+
+WritableSharedMemoryMapping MapAtForTesting(
+ subtle::PlatformSharedMemoryRegion* region,
+ off_t offset,
+ size_t size) {
+ void* memory = nullptr;
+ size_t mapped_size = 0;
+ if (!region->MapAt(offset, size, &memory, &mapped_size))
+ return {};
+
+ return WritableSharedMemoryMapping(memory, size, mapped_size,
+ region->GetGUID());
+}
+
+template <>
+std::pair<ReadOnlySharedMemoryRegion, WritableSharedMemoryMapping>
+CreateMappedRegion(size_t size) {
+ MappedReadOnlyRegion mapped_region = ReadOnlySharedMemoryRegion::Create(size);
+ return {std::move(mapped_region.region), std::move(mapped_region.mapping)};
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_shared_memory_util.h b/chromium/base/test/test_shared_memory_util.h
new file mode 100644
index 00000000000..e23d83e1fee
--- /dev/null
+++ b/chromium/base/test/test_shared_memory_util.h
@@ -0,0 +1,52 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SHARED_MEMORY_UTIL_H_
+#define BASE_TEST_TEST_SHARED_MEMORY_UTIL_H_
+
+#include "base/memory/platform_shared_memory_region.h"
+#include "base/memory/read_only_shared_memory_region.h"
+#include "base/memory/shared_memory_mapping.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Check that the shared memory |region| cannot be used to perform a writable
+// mapping with low-level system APIs like mmap(). Return true in case of
+// success (i.e. writable mappings are _not_ allowed), or false otherwise.
+bool CheckReadOnlyPlatformSharedMemoryRegionForTesting(
+ subtle::PlatformSharedMemoryRegion region);
+
+// Creates a scoped mapping from a PlatformSharedMemoryRegion. It's useful for
+// PlatformSharedMemoryRegion testing to not leak mapped memory.
+// WritableSharedMemoryMapping is used for wrapping because it has max
+// capabilities but the actual permission depends on the |region|'s mode.
+// This must not be used in production where PlatformSharedMemoryRegion should
+// be wrapped with {Writable,Unsafe,ReadOnly}SharedMemoryRegion.
+WritableSharedMemoryMapping MapAtForTesting(
+ subtle::PlatformSharedMemoryRegion* region,
+ off_t offset,
+ size_t size);
+
+WritableSharedMemoryMapping MapForTesting(
+ subtle::PlatformSharedMemoryRegion* region);
+
+template <typename SharedMemoryRegionType>
+std::pair<SharedMemoryRegionType, WritableSharedMemoryMapping>
+CreateMappedRegion(size_t size) {
+ SharedMemoryRegionType region = SharedMemoryRegionType::Create(size);
+ WritableSharedMemoryMapping mapping = region.Map();
+ return {std::move(region), std::move(mapping)};
+}
+
+// Template specialization of CreateMappedRegion<>() for
+// the ReadOnlySharedMemoryRegion. We need this because
+// ReadOnlySharedMemoryRegion::Create() has a different return type.
+template <>
+std::pair<ReadOnlySharedMemoryRegion, WritableSharedMemoryMapping>
+CreateMappedRegion(size_t size);
+
+} // namespace base
+
+#endif // BASE_TEST_TEST_SHARED_MEMORY_UTIL_H_
diff --git a/chromium/base/test/test_shortcut_win.cc b/chromium/base/test/test_shortcut_win.cc
new file mode 100644
index 00000000000..b80fd967ba7
--- /dev/null
+++ b/chromium/base/test/test_shortcut_win.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_shortcut_win.h"
+
+#include <windows.h>
+#include <objbase.h>
+#include <shlobj.h>
+#include <propkey.h>
+#include <wrl/client.h>
+
+#include "base/files/file_path.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/scoped_propvariant.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+void ValidatePathsAreEqual(const FilePath& expected_path,
+ const FilePath& actual_path) {
+ wchar_t long_expected_path_chars[MAX_PATH] = {0};
+ wchar_t long_actual_path_chars[MAX_PATH] = {0};
+
+ // If |expected_path| is empty confirm immediately that |actual_path| is also
+ // empty.
+ if (expected_path.empty()) {
+ EXPECT_TRUE(actual_path.empty());
+ return;
+ }
+
+ // Proceed with LongPathName matching which will also confirm the paths exist.
+ EXPECT_NE(0U, ::GetLongPathName(expected_path.value().c_str(),
+ long_expected_path_chars, MAX_PATH))
+ << "Failed to get LongPathName of " << expected_path.value();
+ EXPECT_NE(0U, ::GetLongPathName(actual_path.value().c_str(),
+ long_actual_path_chars, MAX_PATH))
+ << "Failed to get LongPathName of " << actual_path.value();
+
+ FilePath long_expected_path(long_expected_path_chars);
+ FilePath long_actual_path(long_actual_path_chars);
+ EXPECT_FALSE(long_expected_path.empty());
+ EXPECT_FALSE(long_actual_path.empty());
+
+ EXPECT_EQ(long_expected_path, long_actual_path);
+}
+
+void ValidateShortcut(const FilePath& shortcut_path,
+ const ShortcutProperties& properties) {
+ Microsoft::WRL::ComPtr<IShellLink> i_shell_link;
+ Microsoft::WRL::ComPtr<IPersistFile> i_persist_file;
+
+ wchar_t read_target[MAX_PATH] = {0};
+ wchar_t read_working_dir[MAX_PATH] = {0};
+ wchar_t read_arguments[MAX_PATH] = {0};
+ wchar_t read_description[MAX_PATH] = {0};
+ wchar_t read_icon[MAX_PATH] = {0};
+ int read_icon_index = 0;
+
+ HRESULT hr;
+
+ // Initialize the shell interfaces.
+ EXPECT_TRUE(SUCCEEDED(hr = ::CoCreateInstance(CLSID_ShellLink, NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_PPV_ARGS(&i_shell_link))));
+ if (FAILED(hr))
+ return;
+
+ EXPECT_TRUE(SUCCEEDED(hr = i_shell_link.As(&i_persist_file)));
+ if (FAILED(hr))
+ return;
+
+ // Load the shortcut.
+ EXPECT_TRUE(
+ SUCCEEDED(hr = i_persist_file->Load(shortcut_path.value().c_str(), 0)))
+ << "Failed to load shortcut at " << shortcut_path.value();
+ if (FAILED(hr))
+ return;
+
+ if (properties.options & ShortcutProperties::PROPERTIES_TARGET) {
+ EXPECT_TRUE(SUCCEEDED(
+ i_shell_link->GetPath(read_target, MAX_PATH, NULL, SLGP_SHORTPATH)));
+ ValidatePathsAreEqual(properties.target, FilePath(read_target));
+ }
+
+ if (properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) {
+ EXPECT_TRUE(SUCCEEDED(
+ i_shell_link->GetWorkingDirectory(read_working_dir, MAX_PATH)));
+ ValidatePathsAreEqual(properties.working_dir, FilePath(read_working_dir));
+ }
+
+ if (properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) {
+ EXPECT_TRUE(
+ SUCCEEDED(i_shell_link->GetArguments(read_arguments, MAX_PATH)));
+ EXPECT_EQ(properties.arguments, read_arguments);
+ }
+
+ if (properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) {
+ EXPECT_TRUE(
+ SUCCEEDED(i_shell_link->GetDescription(read_description, MAX_PATH)));
+ EXPECT_EQ(properties.description, read_description);
+ }
+
+ if (properties.options & ShortcutProperties::PROPERTIES_ICON) {
+ EXPECT_TRUE(SUCCEEDED(
+ i_shell_link->GetIconLocation(read_icon, MAX_PATH, &read_icon_index)));
+ ValidatePathsAreEqual(properties.icon, FilePath(read_icon));
+ EXPECT_EQ(properties.icon_index, read_icon_index);
+ }
+
+ Microsoft::WRL::ComPtr<IPropertyStore> property_store;
+ EXPECT_TRUE(SUCCEEDED(hr = i_shell_link.As(&property_store)));
+ if (FAILED(hr))
+ return;
+
+ if (properties.options & ShortcutProperties::PROPERTIES_APP_ID) {
+ ScopedPropVariant pv_app_id;
+ EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_ID,
+ pv_app_id.Receive()));
+ switch (pv_app_id.get().vt) {
+ case VT_EMPTY:
+ EXPECT_TRUE(properties.app_id.empty());
+ break;
+ case VT_LPWSTR:
+ EXPECT_EQ(properties.app_id, pv_app_id.get().pwszVal);
+ break;
+ default:
+ ADD_FAILURE() << "Unexpected variant type: " << pv_app_id.get().vt;
+ }
+ }
+
+ if (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) {
+ ScopedPropVariant pv_dual_mode;
+ EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_IsDualMode,
+ pv_dual_mode.Receive()));
+ switch (pv_dual_mode.get().vt) {
+ case VT_EMPTY:
+ EXPECT_FALSE(properties.dual_mode);
+ break;
+ case VT_BOOL:
+ EXPECT_EQ(properties.dual_mode,
+ static_cast<bool>(pv_dual_mode.get().boolVal));
+ break;
+ default:
+ ADD_FAILURE() << "Unexpected variant type: " << pv_dual_mode.get().vt;
+ }
+ }
+}
+
+} // namespace win
+} // namespace base
diff --git a/chromium/base/test/test_shortcut_win.h b/chromium/base/test/test_shortcut_win.h
new file mode 100644
index 00000000000..b828e8bb1f3
--- /dev/null
+++ b/chromium/base/test/test_shortcut_win.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SHORTCUT_WIN_H_
+#define BASE_TEST_TEST_SHORTCUT_WIN_H_
+
+#include "base/files/file_path.h"
+#include "base/win/shortcut.h"
+
+// Windows shortcut functions used only by tests.
+
+namespace base {
+namespace win {
+
+// Validates |actual_path|'s LongPathName case-insensitively matches
+// |expected_path|'s LongPathName.
+void ValidatePathsAreEqual(const base::FilePath& expected_path,
+ const base::FilePath& actual_path);
+
+// Validates that a shortcut exists at |shortcut_path| with the expected
+// |properties|.
+// Logs gtest failures on failed verifications.
+void ValidateShortcut(const FilePath& shortcut_path,
+ const ShortcutProperties& properties);
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_TEST_TEST_SHORTCUT_WIN_H_
diff --git a/chromium/base/test/test_simple_task_runner.cc b/chromium/base/test/test_simple_task_runner.cc
new file mode 100644
index 00000000000..3e5d70ee4cf
--- /dev/null
+++ b/chromium/base/test/test_simple_task_runner.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_simple_task_runner.h"
+
+#include <utility>
+
+#include "base/check.h"
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace base {
+
+TestSimpleTaskRunner::TestSimpleTaskRunner() = default;
+
+TestSimpleTaskRunner::~TestSimpleTaskRunner() = default;
+
+bool TestSimpleTaskRunner::PostDelayedTask(const Location& from_here,
+ OnceClosure task,
+ TimeDelta delay) {
+ AutoLock auto_lock(lock_);
+ pending_tasks_.push_back(TestPendingTask(from_here, std::move(task),
+ TimeTicks(), delay,
+ TestPendingTask::NESTABLE));
+ return true;
+}
+
+bool TestSimpleTaskRunner::PostNonNestableDelayedTask(const Location& from_here,
+ OnceClosure task,
+ TimeDelta delay) {
+ AutoLock auto_lock(lock_);
+ pending_tasks_.push_back(TestPendingTask(from_here, std::move(task),
+ TimeTicks(), delay,
+ TestPendingTask::NON_NESTABLE));
+ return true;
+}
+
+// TODO(gab): Use SequenceToken here to differentiate between tasks running in
+// the scope of this TestSimpleTaskRunner and other task runners sharing this
+// thread. http://crbug.com/631186
+bool TestSimpleTaskRunner::RunsTasksInCurrentSequence() const {
+ return thread_ref_ == PlatformThread::CurrentRef();
+}
+
+base::circular_deque<TestPendingTask> TestSimpleTaskRunner::TakePendingTasks() {
+ AutoLock auto_lock(lock_);
+ return std::move(pending_tasks_);
+}
+
+size_t TestSimpleTaskRunner::NumPendingTasks() const {
+ AutoLock auto_lock(lock_);
+ return pending_tasks_.size();
+}
+
+bool TestSimpleTaskRunner::HasPendingTask() const {
+ AutoLock auto_lock(lock_);
+ return !pending_tasks_.empty();
+}
+
+base::TimeDelta TestSimpleTaskRunner::NextPendingTaskDelay() const {
+ AutoLock auto_lock(lock_);
+ return pending_tasks_.front().GetTimeToRun() - base::TimeTicks();
+}
+
+base::TimeDelta TestSimpleTaskRunner::FinalPendingTaskDelay() const {
+ AutoLock auto_lock(lock_);
+ return pending_tasks_.back().GetTimeToRun() - base::TimeTicks();
+}
+
+void TestSimpleTaskRunner::ClearPendingTasks() {
+ AutoLock auto_lock(lock_);
+ pending_tasks_.clear();
+}
+
+void TestSimpleTaskRunner::RunPendingTasks() {
+ DCHECK(RunsTasksInCurrentSequence());
+
+ // Swap with a local variable to avoid re-entrancy problems.
+ base::circular_deque<TestPendingTask> tasks_to_run;
+ {
+ AutoLock auto_lock(lock_);
+ tasks_to_run.swap(pending_tasks_);
+ }
+
+ // Multiple test task runners can share the same thread for determinism in
+ // unit tests. Make sure this TestSimpleTaskRunner's tasks run in its scope.
+ ScopedClosureRunner undo_override;
+ if (!ThreadTaskRunnerHandle::IsSet() ||
+ ThreadTaskRunnerHandle::Get() != this) {
+ undo_override = ThreadTaskRunnerHandle::OverrideForTesting(this);
+ }
+
+ for (auto& task : tasks_to_run)
+ std::move(task.task).Run();
+}
+
+void TestSimpleTaskRunner::RunUntilIdle() {
+ while (HasPendingTask())
+ RunPendingTasks();
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_simple_task_runner.h b/chromium/base/test/test_simple_task_runner.h
new file mode 100644
index 00000000000..245ca88c1ce
--- /dev/null
+++ b/chromium/base/test/test_simple_task_runner.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SIMPLE_TASK_RUNNER_H_
+#define BASE_TEST_TEST_SIMPLE_TASK_RUNNER_H_
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/containers/circular_deque.h"
+#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/test/test_pending_task.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+class TimeDelta;
+
+// ATTENTION: Prefer using base::test::TaskEnvironment and a task runner
+// obtained from base/task/post_task.h over this class. This class isn't as
+// "simple" as it seems specifically because it runs tasks in a surprising order
+// (delays aren't respected and nesting doesn't behave as usual). Should you
+// prefer to flush all tasks regardless of delays,
+// TaskEnvironment::TimeSource::MOCK_TIME and
+// TaskEnvironment::FastForwardUntilNoTasksRemain() have you covered.
+//
+// TestSimpleTaskRunner is a simple TaskRunner implementation that can
+// be used for testing. It implements SingleThreadTaskRunner as that
+// interface implements SequencedTaskRunner, which in turn implements
+// TaskRunner, so TestSimpleTaskRunner can be passed in to a function
+// that accepts any *TaskRunner object.
+//
+// TestSimpleTaskRunner has the following properties which make it simple:
+//
+// - Tasks are simply stored in a queue in FIFO order, ignoring delay
+// and nestability.
+// - Tasks aren't guaranteed to be destroyed immediately after
+// they're run.
+//
+// However, TestSimpleTaskRunner allows for reentrancy, in that it
+// handles the running of tasks that in turn call back into itself
+// (e.g., to post more tasks).
+//
+// Note that, like any TaskRunner, TestSimpleTaskRunner is
+// ref-counted.
+class TestSimpleTaskRunner : public SingleThreadTaskRunner {
+ public:
+ TestSimpleTaskRunner();
+
+ // SingleThreadTaskRunner implementation.
+ bool PostDelayedTask(const Location& from_here,
+ OnceClosure task,
+ TimeDelta delay) override;
+ bool PostNonNestableDelayedTask(const Location& from_here,
+ OnceClosure task,
+ TimeDelta delay) override;
+
+ bool RunsTasksInCurrentSequence() const override;
+
+ base::circular_deque<TestPendingTask> TakePendingTasks();
+ size_t NumPendingTasks() const;
+ bool HasPendingTask() const;
+ base::TimeDelta NextPendingTaskDelay() const;
+ base::TimeDelta FinalPendingTaskDelay() const;
+
+ // Clears the queue of pending tasks without running them.
+ void ClearPendingTasks();
+
+ // Runs each current pending task in order and clears the queue. Tasks posted
+ // by the tasks that run within this call do not run within this call. Can
+ // only be called on the thread that created this TestSimpleTaskRunner.
+ void RunPendingTasks();
+
+ // Runs pending tasks until the queue is empty. Can only be called on the
+ // thread that created this TestSimpleTaskRunner.
+ void RunUntilIdle();
+
+ protected:
+ ~TestSimpleTaskRunner() override;
+
+ private:
+ // Thread on which this was instantiated.
+ const PlatformThreadRef thread_ref_ = PlatformThread::CurrentRef();
+
+ // Synchronizes access to |pending_tasks_|.
+ mutable Lock lock_;
+
+ base::circular_deque<TestPendingTask> pending_tasks_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSimpleTaskRunner);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_TEST_SIMPLE_TASK_RUNNER_H_
diff --git a/chromium/base/test/test_suite.cc b/chromium/base/test/test_suite.cc
new file mode 100644
index 00000000000..7aefd46640a
--- /dev/null
+++ b/chromium/base/test/test_suite.cc
@@ -0,0 +1,667 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_suite.h"
+
+#include <signal.h>
+
+#include <memory>
+
+#include "base/at_exit.h"
+#include "base/base_paths.h"
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/debug/profiler.h"
+#include "base/debug/stack_trace.h"
+#include "base/feature_list.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/i18n/icu_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/no_destructor.h"
+#include "base/path_service.h"
+#include "base/process/launch.h"
+#include "base/process/memory.h"
+#include "base/process/process.h"
+#include "base/process/process_handle.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/test/gtest_xml_unittest_result_printer.h"
+#include "base/test/gtest_xml_util.h"
+#include "base/test/icu_test_util.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/mock_entropy_provider.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_run_loop_timeout.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/process/port_provider_mac.h"
+#if defined(OS_IOS)
+#include "base/test/test_listener_ios.h"
+#endif // OS_IOS
+#endif // OS_MACOSX
+
+#include "base/i18n/rtl.h"
+#if !defined(OS_IOS)
+#include "base/strings/string_util.h"
+#include "third_party/icu/source/common/unicode/uloc.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/test/test_support_android.h"
+#endif
+
+#if defined(OS_IOS)
+#include "base/test/test_support_ios.h"
+#endif
+
+#if defined(OS_LINUX)
+#include "base/test/fontconfig_util_linux.h"
+#endif
+
+#if defined(OS_FUCHSIA)
+#include "base/base_paths_fuchsia.h"
+#endif
+
+#if defined(OS_WIN) && defined(_DEBUG)
+#include <crtdbg.h>
+#endif
+
+namespace base {
+
+namespace {
+
+// Returns true if the test is marked as "MAYBE_".
+// When using different prefixes depending on platform, we use MAYBE_ and
+// preprocessor directives to replace MAYBE_ with the target prefix.
+bool IsMarkedMaybe(const testing::TestInfo& test) {
+ return strncmp(test.name(), "MAYBE_", 6) == 0;
+}
+
+class DisableMaybeTests : public testing::EmptyTestEventListener {
+ public:
+ void OnTestStart(const testing::TestInfo& test_info) override {
+ ASSERT_FALSE(IsMarkedMaybe(test_info))
+ << "Probably the OS #ifdefs don't include all of the necessary "
+ "platforms.\nPlease ensure that no tests have the MAYBE_ prefix "
+ "after the code is preprocessed.";
+ }
+};
+
+class ResetCommandLineBetweenTests : public testing::EmptyTestEventListener {
+ public:
+ ResetCommandLineBetweenTests() : old_command_line_(CommandLine::NO_PROGRAM) {}
+
+ void OnTestStart(const testing::TestInfo& test_info) override {
+ old_command_line_ = *CommandLine::ForCurrentProcess();
+ }
+
+ void OnTestEnd(const testing::TestInfo& test_info) override {
+ *CommandLine::ForCurrentProcess() = old_command_line_;
+ }
+
+ private:
+ CommandLine old_command_line_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResetCommandLineBetweenTests);
+};
+
+// Initializes a base::test::ScopedFeatureList for each individual test, which
+// involves a FeatureList and a FieldTrialList, such that unit test don't need
+// to initialize them manually.
+class FeatureListScopedToEachTest : public testing::EmptyTestEventListener {
+ public:
+ FeatureListScopedToEachTest() = default;
+ ~FeatureListScopedToEachTest() override = default;
+
+ FeatureListScopedToEachTest(const FeatureListScopedToEachTest&) = delete;
+ FeatureListScopedToEachTest& operator=(const FeatureListScopedToEachTest&) =
+ delete;
+
+ void OnTestStart(const testing::TestInfo& test_info) override {
+ field_trial_list_ = std::make_unique<FieldTrialList>(
+ std::make_unique<MockEntropyProvider>());
+
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+
+ // Set up a FeatureList instance, so that code using that API will not hit a
+ // an error that it's not set. It will be cleared automatically.
+ // TestFeatureForBrowserTest1 and TestFeatureForBrowserTest2 used in
+ // ContentBrowserTestScopedFeatureListTest to ensure ScopedFeatureList keeps
+ // features from command line.
+ std::string enabled =
+ command_line->GetSwitchValueASCII(switches::kEnableFeatures);
+ std::string disabled =
+ command_line->GetSwitchValueASCII(switches::kDisableFeatures);
+ enabled += ",TestFeatureForBrowserTest1";
+ disabled += ",TestFeatureForBrowserTest2";
+ scoped_feature_list_.InitFromCommandLine(enabled, disabled);
+
+ // The enable-features and disable-features flags were just slurped into a
+ // FeatureList, so remove them from the command line. Tests should enable
+ // and disable features via the ScopedFeatureList API rather than
+ // command-line flags.
+ CommandLine new_command_line(command_line->GetProgram());
+ CommandLine::SwitchMap switches = command_line->GetSwitches();
+
+ switches.erase(switches::kEnableFeatures);
+ switches.erase(switches::kDisableFeatures);
+
+ for (const auto& iter : switches)
+ new_command_line.AppendSwitchNative(iter.first, iter.second);
+
+ *CommandLine::ForCurrentProcess() = new_command_line;
+ }
+
+ void OnTestEnd(const testing::TestInfo& test_info) override {
+ scoped_feature_list_.Reset();
+ field_trial_list_.reset();
+ }
+
+ private:
+ std::unique_ptr<FieldTrialList> field_trial_list_;
+ test::ScopedFeatureList scoped_feature_list_;
+};
+
+class CheckForLeakedGlobals : public testing::EmptyTestEventListener {
+ public:
+ CheckForLeakedGlobals() = default;
+
+ // Check for leaks in individual tests.
+ void OnTestStart(const testing::TestInfo& test) override {
+ feature_list_set_before_test_ = FeatureList::GetInstance();
+ thread_pool_set_before_test_ = ThreadPoolInstance::Get();
+ }
+ void OnTestEnd(const testing::TestInfo& test) override {
+ DCHECK_EQ(feature_list_set_before_test_, FeatureList::GetInstance())
+ << " in test " << test.test_case_name() << "." << test.name();
+ DCHECK_EQ(thread_pool_set_before_test_, ThreadPoolInstance::Get())
+ << " in test " << test.test_case_name() << "." << test.name();
+ }
+
+ // Check for leaks in test cases (consisting of one or more tests).
+ void OnTestCaseStart(const testing::TestCase& test_case) override {
+ feature_list_set_before_case_ = FeatureList::GetInstance();
+ thread_pool_set_before_case_ = ThreadPoolInstance::Get();
+ }
+ void OnTestCaseEnd(const testing::TestCase& test_case) override {
+ DCHECK_EQ(feature_list_set_before_case_, FeatureList::GetInstance())
+ << " in case " << test_case.name();
+ DCHECK_EQ(thread_pool_set_before_case_, ThreadPoolInstance::Get())
+ << " in case " << test_case.name();
+ }
+
+ private:
+ FeatureList* feature_list_set_before_test_ = nullptr;
+ FeatureList* feature_list_set_before_case_ = nullptr;
+ ThreadPoolInstance* thread_pool_set_before_test_ = nullptr;
+ ThreadPoolInstance* thread_pool_set_before_case_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(CheckForLeakedGlobals);
+};
+
+// base::Process is not available on iOS
+#if !defined(OS_IOS)
+class CheckProcessPriority : public testing::EmptyTestEventListener {
+ public:
+ CheckProcessPriority() { CHECK(!IsProcessBackgrounded()); }
+
+ void OnTestStart(const testing::TestInfo& test) override {
+ EXPECT_FALSE(IsProcessBackgrounded());
+ }
+ void OnTestEnd(const testing::TestInfo& test) override {
+#if !defined(OS_MACOSX)
+ // Flakes are found on Mac OS 10.11. See https://crbug.com/931721#c7.
+ EXPECT_FALSE(IsProcessBackgrounded());
+#endif
+ }
+
+ private:
+#if defined(OS_MACOSX)
+ // Returns the calling process's task port, ignoring its argument.
+ class CurrentProcessPortProvider : public PortProvider {
+ mach_port_t TaskForPid(ProcessHandle process) const override {
+ // This PortProvider implementation only works for the current process.
+ CHECK_EQ(process, base::GetCurrentProcessHandle());
+ return mach_task_self();
+ }
+ };
+#endif
+
+ bool IsProcessBackgrounded() const {
+#if defined(OS_MACOSX)
+ CurrentProcessPortProvider port_provider;
+ return Process::Current().IsProcessBackgrounded(&port_provider);
+#else
+ return Process::Current().IsProcessBackgrounded();
+#endif
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(CheckProcessPriority);
+};
+#endif // !defined(OS_IOS)
+
+class CheckThreadPriority : public testing::EmptyTestEventListener {
+ public:
+ CheckThreadPriority(bool check_thread_priority_at_test_end)
+ : check_thread_priority_at_test_end_(check_thread_priority_at_test_end) {
+ CHECK_EQ(base::PlatformThread::GetCurrentThreadPriority(),
+ base::ThreadPriority::NORMAL)
+ << " -- The thread priority of this process is not the default. This "
+ "usually indicates nice has been used, which is not supported.";
+ }
+
+ void OnTestStart(const testing::TestInfo& test) override {
+ EXPECT_EQ(base::PlatformThread::GetCurrentThreadPriority(),
+ base::ThreadPriority::NORMAL)
+ << " -- The thread priority of this process is not the default. This "
+ "usually indicates nice has been used, which is not supported.";
+ }
+ void OnTestEnd(const testing::TestInfo& test) override {
+ if (check_thread_priority_at_test_end_) {
+ EXPECT_EQ(base::PlatformThread::GetCurrentThreadPriority(),
+ base::ThreadPriority::NORMAL)
+ << " -- The thread priority of this process is not the default. This "
+ "usually indicates nice has been used, which is not supported.";
+ }
+ }
+
+ private:
+ const bool check_thread_priority_at_test_end_;
+
+ DISALLOW_COPY_AND_ASSIGN(CheckThreadPriority);
+};
+
+const std::string& GetProfileName() {
+ static const NoDestructor<std::string> profile_name([]() {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kProfilingFile))
+ return command_line.GetSwitchValueASCII(switches::kProfilingFile);
+ else
+ return std::string("test-profile-{pid}");
+ }());
+ return *profile_name;
+}
+
+void InitializeLogging() {
+#if defined(OS_ANDROID)
+ InitAndroidTestLogging();
+#else
+
+ FilePath log_filename;
+ FilePath exe;
+ PathService::Get(FILE_EXE, &exe);
+
+#if defined(OS_FUCHSIA)
+ // Write logfiles to /data, because the default log location alongside the
+ // executable (/pkg) is read-only.
+ FilePath data_dir;
+ PathService::Get(DIR_APP_DATA, &data_dir);
+ log_filename = data_dir.Append(exe.BaseName())
+ .ReplaceExtension(FILE_PATH_LITERAL("log"));
+#else
+ log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
+#endif // defined(OS_FUCHSIA)
+
+ logging::LoggingSettings settings;
+ settings.log_file_path = log_filename.value().c_str();
+ settings.logging_dest = logging::LOG_TO_ALL;
+ settings.delete_old = logging::DELETE_OLD_LOG_FILE;
+ logging::InitLogging(settings);
+ // We want process and thread IDs because we may have multiple processes.
+ // Note: temporarily enabled timestamps in an effort to catch bug 6361.
+ logging::SetLogItems(true, true, true, true);
+#endif // !defined(OS_ANDROID)
+}
+
+} // namespace
+
+int RunUnitTestsUsingBaseTestSuite(int argc, char** argv) {
+ TestSuite test_suite(argc, argv);
+ return LaunchUnitTests(argc, argv,
+ BindOnce(&TestSuite::Run, Unretained(&test_suite)));
+}
+
+TestSuite::TestSuite(int argc, char** argv) {
+ PreInitialize();
+ InitializeFromCommandLine(argc, argv);
+ // Logging must be initialized before any thread has a chance to call logging
+ // functions.
+ InitializeLogging();
+}
+
+#if defined(OS_WIN)
+TestSuite::TestSuite(int argc, wchar_t** argv) {
+ PreInitialize();
+ InitializeFromCommandLine(argc, argv);
+ // Logging must be initialized before any thread has a chance to call logging
+ // functions.
+ InitializeLogging();
+}
+#endif // defined(OS_WIN)
+
+TestSuite::~TestSuite() {
+ if (initialized_command_line_)
+ CommandLine::Reset();
+}
+
+void TestSuite::InitializeFromCommandLine(int argc, char** argv) {
+ initialized_command_line_ = CommandLine::Init(argc, argv);
+ testing::InitGoogleTest(&argc, argv);
+ testing::InitGoogleMock(&argc, argv);
+
+#if defined(OS_IOS)
+ InitIOSRunHook(this, argc, argv);
+#endif
+}
+
+#if defined(OS_WIN)
+void TestSuite::InitializeFromCommandLine(int argc, wchar_t** argv) {
+ // Windows CommandLine::Init ignores argv anyway.
+ initialized_command_line_ = CommandLine::Init(argc, NULL);
+ testing::InitGoogleTest(&argc, argv);
+ testing::InitGoogleMock(&argc, argv);
+}
+#endif // defined(OS_WIN)
+
+void TestSuite::PreInitialize() {
+ DCHECK(!is_initialized_);
+
+#if defined(OS_WIN)
+ testing::GTEST_FLAG(catch_exceptions) = false;
+#endif
+ EnableTerminationOnHeapCorruption();
+#if defined(OS_LINUX) && defined(USE_AURA)
+ // When calling native char conversion functions (e.g wrctomb) we need to
+ // have the locale set. In the absence of such a call the "C" locale is the
+ // default. In the gtk code (below) gtk_init() implicitly sets a locale.
+ setlocale(LC_ALL, "");
+ // We still need number to string conversions to be locale insensitive.
+ setlocale(LC_NUMERIC, "C");
+#endif // defined(OS_LINUX) && defined(USE_AURA)
+
+ // On Android, AtExitManager is created in
+ // testing/android/native_test_wrapper.cc before main() is called.
+#if !defined(OS_ANDROID)
+ at_exit_manager_.reset(new AtExitManager);
+#endif
+
+ // Don't add additional code to this function. Instead add it to
+ // Initialize(). See bug 6436.
+}
+
+void TestSuite::AddTestLauncherResultPrinter() {
+ // Only add the custom printer if requested.
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kTestLauncherOutput)) {
+ return;
+ }
+
+ FilePath output_path(CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kTestLauncherOutput));
+
+ // Do not add the result printer if output path already exists. It's an
+ // indicator there is a process printing to that file, and we're likely
+ // its child. Do not clobber the results in that case.
+ if (PathExists(output_path)) {
+ LOG(WARNING) << "Test launcher output path " << output_path.AsUTF8Unsafe()
+ << " exists. Not adding test launcher result printer.";
+ return;
+ }
+
+ printer_ = new XmlUnitTestResultPrinter;
+ CHECK(printer_->Initialize(output_path))
+ << "Output path is " << output_path.AsUTF8Unsafe()
+ << " and PathExists(output_path) is " << PathExists(output_path);
+ testing::TestEventListeners& listeners =
+ testing::UnitTest::GetInstance()->listeners();
+ listeners.Append(printer_);
+}
+
+// Don't add additional code to this method. Instead add it to
+// Initialize(). See bug 6436.
+int TestSuite::Run() {
+#if defined(OS_IOS)
+ RunTestsFromIOSApp();
+#endif
+
+#if defined(OS_MACOSX)
+ mac::ScopedNSAutoreleasePool scoped_pool;
+#endif
+
+ Initialize();
+ std::string client_func =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kTestChildProcess);
+
+ // Check to see if we are being run as a client process.
+ if (!client_func.empty())
+ return multi_process_function_list::InvokeChildProcessTest(client_func);
+#if defined(OS_IOS)
+ test_listener_ios::RegisterTestEndListener();
+#endif
+
+ int result = RUN_ALL_TESTS();
+
+#if defined(OS_MACOSX)
+ // This MUST happen before Shutdown() since Shutdown() tears down
+ // objects (such as NotificationService::current()) that Cocoa
+ // objects use to remove themselves as observers.
+ scoped_pool.Recycle();
+#endif
+
+ Shutdown();
+
+ return result;
+}
+
+void TestSuite::DisableCheckForLeakedGlobals() {
+ DCHECK(!is_initialized_);
+ check_for_leaked_globals_ = false;
+}
+
+void TestSuite::DisableCheckForThreadAndProcessPriority() {
+ DCHECK(!is_initialized_);
+ check_for_thread_and_process_priority_ = false;
+}
+
+void TestSuite::DisableCheckForThreadPriorityAtTestEnd() {
+ DCHECK(!is_initialized_);
+ check_for_thread_priority_at_test_end_ = false;
+}
+
+void TestSuite::UnitTestAssertHandler(const char* file,
+ int line,
+ const StringPiece summary,
+ const StringPiece stack_trace) {
+#if defined(OS_ANDROID)
+ // Correlating test stdio with logcat can be difficult, so we emit this
+ // helpful little hint about what was running. Only do this for Android
+ // because other platforms don't separate out the relevant logs in the same
+ // way.
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ if (test_info) {
+ LOG(ERROR) << "Currently running: " << test_info->test_case_name() << "."
+ << test_info->name();
+ fflush(stderr);
+ }
+#endif // defined(OS_ANDROID)
+
+ // XmlUnitTestResultPrinter inherits gtest format, where assert has summary
+ // and message. In GTest, summary is just a logged text, and message is a
+ // logged text, concatenated with stack trace of assert.
+ // Concatenate summary and stack_trace here, to pass it as a message.
+ if (printer_) {
+ const std::string summary_str = summary.as_string();
+ const std::string stack_trace_str = summary_str + stack_trace.as_string();
+ printer_->OnAssert(file, line, summary_str, stack_trace_str);
+ }
+
+ // The logging system actually prints the message before calling the assert
+ // handler. Just exit now to avoid printing too many stack traces.
+ _exit(1);
+}
+
+#if defined(OS_WIN)
+namespace {
+
+// Handlers for invalid parameter, pure call, and abort. They generate a
+// breakpoint to ensure that we get a call stack on these failures.
+// These functions should be written to be unique in order to avoid confusing
+// call stacks from /OPT:ICF function folding. Printing a unique message or
+// returning a unique value will do this. Note that for best results they need
+// to be unique from *all* functions in Chrome.
+void InvalidParameter(const wchar_t* expression,
+ const wchar_t* function,
+ const wchar_t* file,
+ unsigned int line,
+ uintptr_t reserved) {
+ // CRT printed message is sufficient.
+ __debugbreak();
+ _exit(1);
+}
+
+void PureCall() {
+ fprintf(stderr, "Pure-virtual function call. Terminating.\n");
+ __debugbreak();
+ _exit(1);
+}
+
+void AbortHandler(int signal) {
+ // Print EOL after the CRT abort message.
+ fprintf(stderr, "\n");
+ __debugbreak();
+}
+
+} // namespace
+#endif
+
+void TestSuite::SuppressErrorDialogs() {
+#if defined(OS_WIN)
+ UINT new_flags =
+ SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
+
+ // Preserve existing error mode, as discussed at
+ // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx
+ UINT existing_flags = SetErrorMode(new_flags);
+ SetErrorMode(existing_flags | new_flags);
+
+#if defined(_DEBUG)
+ // Suppress the "Debug Assertion Failed" dialog.
+ // TODO(hbono): remove this code when gtest has it.
+ // http://groups.google.com/d/topic/googletestframework/OjuwNlXy5ac/discussion
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+#endif // defined(_DEBUG)
+
+ // See crbug.com/783040 for test code to trigger all of these failures.
+ _set_invalid_parameter_handler(InvalidParameter);
+ _set_purecall_handler(PureCall);
+ signal(SIGABRT, AbortHandler);
+#endif // defined(OS_WIN)
+}
+
+void TestSuite::Initialize() {
+ DCHECK(!is_initialized_);
+
+ test::ScopedRunLoopTimeout::SetAddGTestFailureOnTimeout();
+
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+#if !defined(OS_IOS)
+ if (command_line->HasSwitch(switches::kWaitForDebugger)) {
+ debug::WaitForDebugger(60, true);
+ }
+#endif
+
+#if defined(OS_IOS)
+ InitIOSTestMessageLoop();
+#endif // OS_IOS
+
+#if defined(OS_ANDROID)
+ InitAndroidTestMessageLoop();
+#endif // else defined(OS_ANDROID)
+
+ CHECK(debug::EnableInProcessStackDumping());
+#if defined(OS_WIN)
+ RouteStdioToConsole(true);
+ // Make sure we run with high resolution timer to minimize differences
+ // between production code and test code.
+ Time::EnableHighResolutionTimer(true);
+#endif // defined(OS_WIN)
+
+ // In some cases, we do not want to see standard error dialogs.
+ if (!debug::BeingDebugged() &&
+ !command_line->HasSwitch("show-error-dialogs")) {
+ SuppressErrorDialogs();
+ debug::SetSuppressDebugUI(true);
+ assert_handler_ = std::make_unique<logging::ScopedLogAssertHandler>(
+ BindRepeating(&TestSuite::UnitTestAssertHandler, Unretained(this)));
+ }
+
+ test::InitializeICUForTesting();
+
+ // A number of tests only work if the locale is en_US. This can be an issue
+ // on all platforms. To fix this we force the default locale to en_US. This
+ // does not affect tests that explicitly overrides the locale for testing.
+ // TODO(jshin): Should we set the locale via an OS X locale API here?
+ i18n::SetICUDefaultLocale("en_US");
+
+#if defined(OS_LINUX)
+ SetUpFontconfig();
+#endif
+
+ // Add TestEventListeners to enforce certain properties across tests.
+ testing::TestEventListeners& listeners =
+ testing::UnitTest::GetInstance()->listeners();
+ listeners.Append(new DisableMaybeTests);
+ listeners.Append(new ResetCommandLineBetweenTests);
+ listeners.Append(new FeatureListScopedToEachTest);
+ if (check_for_leaked_globals_)
+ listeners.Append(new CheckForLeakedGlobals);
+ if (check_for_thread_and_process_priority_) {
+#if !defined(OS_ANDROID)
+ // TODO(https://crbug.com/931706): Check thread priority on Android.
+ listeners.Append(
+ new CheckThreadPriority(check_for_thread_priority_at_test_end_));
+#endif
+#if !defined(OS_IOS)
+ listeners.Append(new CheckProcessPriority);
+#endif
+ }
+
+ AddTestLauncherResultPrinter();
+
+ TestTimeouts::Initialize();
+
+ trace_to_file_.BeginTracingFromCommandLineOptions();
+
+ debug::StartProfiling(GetProfileName());
+
+ debug::VerifyDebugger();
+
+ is_initialized_ = true;
+}
+
+void TestSuite::Shutdown() {
+ DCHECK(is_initialized_);
+ debug::StopProfiling();
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_suite.h b/chromium/base/test/test_suite.h
new file mode 100644
index 00000000000..372c5f58a8a
--- /dev/null
+++ b/chromium/base/test/test_suite.h
@@ -0,0 +1,110 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SUITE_H_
+#define BASE_TEST_TEST_SUITE_H_
+
+// Defines a basic test suite framework for running gtest based tests. You can
+// instantiate this class in your main function and call its Run method to run
+// any gtest based tests that are linked into your executable.
+
+#include <memory>
+#include <string>
+
+#include "base/at_exit.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/test/trace_to_file.h"
+#include "build/build_config.h"
+
+namespace testing {
+class TestInfo;
+}
+
+namespace base {
+
+class XmlUnitTestResultPrinter;
+
+// Instantiates TestSuite, runs it and returns exit code.
+int RunUnitTestsUsingBaseTestSuite(int argc, char** argv);
+
+class TestSuite {
+ public:
+ // Match function used by the GetTestCount method.
+ typedef bool (*TestMatch)(const testing::TestInfo&);
+
+ TestSuite(int argc, char** argv);
+#if defined(OS_WIN)
+ TestSuite(int argc, wchar_t** argv);
+#endif // defined(OS_WIN)
+ virtual ~TestSuite();
+
+ int Run();
+
+ // Disables checks for thread and process priority at the beginning and end of
+ // each test. Most tests should not use this.
+ void DisableCheckForThreadAndProcessPriority();
+
+ // Disables checks for thread priority at the end of each test (still checks
+ // at the beginning of each test). This should be used for tests that run in
+ // their own process and should start with normal priorities but are allowed
+ // to end with different priorities.
+ void DisableCheckForThreadPriorityAtTestEnd();
+
+ // Disables checks for certain global objects being leaked across tests.
+ void DisableCheckForLeakedGlobals();
+
+ protected:
+ // By default fatal log messages (e.g. from DCHECKs) result in error dialogs
+ // which gum up buildbots. Use a minimalistic assert handler which just
+ // terminates the process.
+ void UnitTestAssertHandler(const char* file,
+ int line,
+ const base::StringPiece summary,
+ const base::StringPiece stack_trace);
+
+ // Disable crash dialogs so that it doesn't gum up the buildbot
+ virtual void SuppressErrorDialogs();
+
+ // Override these for custom initialization and shutdown handling. Use these
+ // instead of putting complex code in your constructor/destructor.
+
+ virtual void Initialize();
+ virtual void Shutdown();
+
+ // Make sure that we setup an AtExitManager so Singleton objects will be
+ // destroyed.
+ std::unique_ptr<base::AtExitManager> at_exit_manager_;
+
+ private:
+ void AddTestLauncherResultPrinter();
+
+ void InitializeFromCommandLine(int argc, char** argv);
+#if defined(OS_WIN)
+ void InitializeFromCommandLine(int argc, wchar_t** argv);
+#endif // defined(OS_WIN)
+
+ // Basic initialization for the test suite happens here.
+ void PreInitialize();
+
+ test::TraceToFile trace_to_file_;
+
+ bool initialized_command_line_ = false;
+
+ XmlUnitTestResultPrinter* printer_ = nullptr;
+
+ std::unique_ptr<logging::ScopedLogAssertHandler> assert_handler_;
+
+ bool check_for_leaked_globals_ = true;
+ bool check_for_thread_and_process_priority_ = true;
+ bool check_for_thread_priority_at_test_end_ = true;
+
+ bool is_initialized_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSuite);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_TEST_SUITE_H_
diff --git a/chromium/base/test/test_support_android.cc b/chromium/base/test/test_support_android.cc
new file mode 100644
index 00000000000..0a8a5b2db18
--- /dev/null
+++ b/chromium/base/test/test_support_android.cc
@@ -0,0 +1,223 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "base/android/path_utils.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/singleton.h"
+#include "base/message_loop/message_pump.h"
+#include "base/message_loop/message_pump_android.h"
+#include "base/path_service.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/multiprocess_test.h"
+
+namespace {
+
+base::FilePath* g_test_data_dir = nullptr;
+
+struct RunState {
+ RunState(base::MessagePump::Delegate* delegate, int run_depth)
+ : delegate(delegate),
+ run_depth(run_depth),
+ should_quit(false) {
+ }
+
+ base::MessagePump::Delegate* delegate;
+
+ // Used to count how many Run() invocations are on the stack.
+ int run_depth;
+
+ // Used to flag that the current Run() invocation should return ASAP.
+ bool should_quit;
+};
+
+RunState* g_state = nullptr;
+
+// A singleton WaitableEvent wrapper so we avoid a busy loop in
+// MessagePumpForUIStub. Other platforms use the native event loop which blocks
+// when there are no pending messages.
+class Waitable {
+ public:
+ static Waitable* GetInstance() {
+ return base::Singleton<Waitable,
+ base::LeakySingletonTraits<Waitable>>::get();
+ }
+
+ // Signals that there are more work to do.
+ void Signal() { waitable_event_.Signal(); }
+
+ // Blocks until more work is scheduled.
+ void Block() { waitable_event_.Wait(); }
+
+ void Quit() {
+ g_state->should_quit = true;
+ Signal();
+ }
+
+ private:
+ friend struct base::DefaultSingletonTraits<Waitable>;
+
+ Waitable()
+ : waitable_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+ base::WaitableEvent waitable_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(Waitable);
+};
+
+// The MessagePumpForUI implementation for test purpose.
+class MessagePumpForUIStub : public base::MessagePumpForUI {
+ public:
+ MessagePumpForUIStub() : base::MessagePumpForUI() { Waitable::GetInstance(); }
+ ~MessagePumpForUIStub() override {}
+
+ bool IsTestImplementation() const override { return true; }
+
+ // In tests, there isn't a native thread, as such RunLoop::Run() should be
+ // used to run the loop instead of attaching and delegating to the native
+ // loop. As such, this override ignores the Attach() request.
+ void Attach(base::MessagePump::Delegate* delegate) override {}
+
+ void Run(base::MessagePump::Delegate* delegate) override {
+ // The following was based on message_pump_glib.cc, except we're using a
+ // WaitableEvent since there are no native message loop to use.
+ RunState state(delegate, g_state ? g_state->run_depth + 1 : 1);
+
+ RunState* previous_state = g_state;
+ g_state = &state;
+
+ // When not nested we can use the real implementation, otherwise fall back
+ // to the stub implementation.
+ if (g_state->run_depth > 1) {
+ RunNested(delegate);
+ } else {
+ MessagePumpForUI::Run(delegate);
+ }
+
+ g_state = previous_state;
+ }
+
+ void RunNested(base::MessagePump::Delegate* delegate) {
+ bool more_work_is_plausible = true;
+
+ for (;;) {
+ if (!more_work_is_plausible) {
+ Waitable::GetInstance()->Block();
+ if (g_state->should_quit)
+ break;
+ }
+
+ Delegate::NextWorkInfo next_work_info = g_state->delegate->DoWork();
+ more_work_is_plausible = next_work_info.is_immediate();
+ if (g_state->should_quit)
+ break;
+
+ if (more_work_is_plausible)
+ continue;
+
+ more_work_is_plausible = g_state->delegate->DoIdleWork();
+ if (g_state->should_quit)
+ break;
+
+ more_work_is_plausible |= !next_work_info.delayed_run_time.is_max();
+ }
+ }
+
+ void Quit() override {
+ CHECK(g_state);
+ if (g_state->run_depth > 1) {
+ Waitable::GetInstance()->Quit();
+ } else {
+ MessagePumpForUI::Quit();
+ }
+ }
+
+ void ScheduleWork() override {
+ if (g_state && g_state->run_depth > 1) {
+ Waitable::GetInstance()->Signal();
+ } else {
+ MessagePumpForUI::ScheduleWork();
+ }
+ }
+
+ void ScheduleDelayedWork(const base::TimeTicks& delayed_work_time) override {
+ if (g_state && g_state->run_depth > 1) {
+ Waitable::GetInstance()->Signal();
+ } else {
+ MessagePumpForUI::ScheduleDelayedWork(delayed_work_time);
+ }
+ }
+};
+
+std::unique_ptr<base::MessagePump> CreateMessagePumpForUIStub() {
+ return std::unique_ptr<base::MessagePump>(new MessagePumpForUIStub());
+}
+
+// Provides the test path for DIR_SOURCE_ROOT and DIR_ANDROID_APP_DATA.
+bool GetTestProviderPath(int key, base::FilePath* result) {
+ switch (key) {
+ // TODO(agrieve): Stop overriding DIR_ANDROID_APP_DATA.
+ // https://crbug.com/617734
+ // Instead DIR_ASSETS should be used to discover assets file location in
+ // tests.
+ case base::DIR_ANDROID_APP_DATA:
+ case base::DIR_ASSETS:
+ case base::DIR_SOURCE_ROOT:
+ CHECK(g_test_data_dir != nullptr);
+ *result = *g_test_data_dir;
+ return true;
+ default:
+ return false;
+ }
+}
+
+void InitPathProvider(int key) {
+ base::FilePath path;
+ // If failed to override the key, that means the way has not been registered.
+ if (GetTestProviderPath(key, &path) &&
+ !base::PathService::Override(key, path)) {
+ base::PathService::RegisterProvider(&GetTestProviderPath, key, key + 1);
+ }
+}
+
+} // namespace
+
+namespace base {
+
+void InitAndroidTestLogging() {
+ logging::LoggingSettings settings;
+ settings.logging_dest =
+ logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
+ logging::InitLogging(settings);
+ // To view log output with IDs and timestamps use "adb logcat -v threadtime".
+ logging::SetLogItems(false, // Process ID
+ false, // Thread ID
+ false, // Timestamp
+ false); // Tick count
+}
+
+void InitAndroidTestPaths(const FilePath& test_data_dir) {
+ if (g_test_data_dir) {
+ CHECK(test_data_dir == *g_test_data_dir);
+ return;
+ }
+ g_test_data_dir = new FilePath(test_data_dir);
+ InitPathProvider(DIR_SOURCE_ROOT);
+ InitPathProvider(DIR_ANDROID_APP_DATA);
+ InitPathProvider(DIR_ASSETS);
+}
+
+void InitAndroidTestMessageLoop() {
+ // NOTE something else such as a JNI call may have already overridden the UI
+ // factory.
+ if (!MessagePump::IsMessagePumpForUIFactoryOveridden())
+ MessagePump::OverrideMessagePumpForUIFactory(&CreateMessagePumpForUIStub);
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_support_android.h b/chromium/base/test/test_support_android.h
new file mode 100644
index 00000000000..4942e546110
--- /dev/null
+++ b/chromium/base/test/test_support_android.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SUPPORT_ANDROID_H_
+#define BASE_TEST_TEST_SUPPORT_ANDROID_H_
+
+#include "base/base_export.h"
+
+namespace base {
+
+class FilePath;
+
+// Init logging for tests on Android. Logs will be output into Android's logcat.
+BASE_EXPORT void InitAndroidTestLogging();
+
+// Init path providers for tests on Android.
+BASE_EXPORT void InitAndroidTestPaths(const FilePath& test_data_dir);
+
+// Init the message loop for tests on Android.
+BASE_EXPORT void InitAndroidTestMessageLoop();
+
+} // namespace base
+
+#endif // BASE_TEST_TEST_SUPPORT_ANDROID_H_
diff --git a/chromium/base/test/test_support_ios.h b/chromium/base/test/test_support_ios.h
new file mode 100644
index 00000000000..9064cb0973f
--- /dev/null
+++ b/chromium/base/test/test_support_ios.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SUPPORT_IOS_H_
+#define BASE_TEST_TEST_SUPPORT_IOS_H_
+
+#include "base/test/test_suite.h"
+
+namespace base {
+
+// Inits the message loop for tests on iOS.
+void InitIOSTestMessageLoop();
+
+// Inits the run hook for tests on iOS.
+void InitIOSRunHook(TestSuite* suite, int argc, char* argv[]);
+
+// Launches an iOS app that runs the tests in the suite passed to
+// InitIOSRunHook.
+void RunTestsFromIOSApp();
+
+// Returns true if unittests should be run by the XCTest runnner.
+bool ShouldRunIOSUnittestsWithXCTest();
+
+} // namespace base
+
+#endif // BASE_TEST_TEST_SUPPORT_IOS_H_
diff --git a/chromium/base/test/test_support_ios.mm b/chromium/base/test/test_support_ios.mm
new file mode 100644
index 00000000000..be949a11ee8
--- /dev/null
+++ b/chromium/base/test/test_support_ios.mm
@@ -0,0 +1,246 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/test/test_support_ios.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/check.h"
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/message_loop/message_pump.h"
+#include "base/message_loop/message_pump_mac.h"
+#import "base/test/ios/google_test_runner_delegate.h"
+#include "base/test/test_suite.h"
+#include "base/test/test_switches.h"
+#include "testing/coverage_util_ios.h"
+
+// Springboard will kill any iOS app that fails to check in after launch within
+// a given time. Starting a UIApplication before invoking TestSuite::Run
+// prevents this from happening.
+
+// InitIOSRunHook saves the TestSuite and argc/argv, then invoking
+// RunTestsFromIOSApp calls UIApplicationMain(), providing an application
+// delegate class: ChromeUnitTestDelegate. The delegate implements
+// application:didFinishLaunchingWithOptions: to invoke the TestSuite's Run
+// method.
+
+// Since the executable isn't likely to be a real iOS UI, the delegate puts up a
+// window displaying the app name. If a bunch of apps using MainHook are being
+// run in a row, this provides an indication of which one is currently running.
+
+static base::TestSuite* g_test_suite = NULL;
+static int g_argc;
+static char** g_argv;
+
+@interface UIApplication (Testing)
+- (void)_terminateWithStatus:(int)status;
+@end
+
+#if TARGET_IPHONE_SIMULATOR
+// Xcode 6 introduced behavior in the iOS Simulator where the software
+// keyboard does not appear if a hardware keyboard is connected. The following
+// declaration allows this behavior to be overriden when the app starts up.
+@interface UIKeyboardImpl
++ (instancetype)sharedInstance;
+- (void)setAutomaticMinimizationEnabled:(BOOL)enabled;
+- (void)setSoftwareKeyboardShownByTouch:(BOOL)enabled;
+@end
+#endif // TARGET_IPHONE_SIMULATOR
+
+@interface ChromeUnitTestDelegate : NSObject <GoogleTestRunnerDelegate> {
+ base::scoped_nsobject<UIWindow> _window;
+}
+- (void)runTests;
+@end
+
+@implementation ChromeUnitTestDelegate
+
+- (BOOL)application:(UIApplication *)application
+ didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+#if TARGET_IPHONE_SIMULATOR
+ // Xcode 6 introduced behavior in the iOS Simulator where the software
+ // keyboard does not appear if a hardware keyboard is connected. The following
+ // calls override this behavior by ensuring that the software keyboard is
+ // always shown.
+ [[UIKeyboardImpl sharedInstance] setAutomaticMinimizationEnabled:NO];
+ [[UIKeyboardImpl sharedInstance] setSoftwareKeyboardShownByTouch:YES];
+#endif // TARGET_IPHONE_SIMULATOR
+
+ CGRect bounds = [[UIScreen mainScreen] bounds];
+
+ // Yes, this is leaked, it's just to make what's running visible.
+ _window.reset([[UIWindow alloc] initWithFrame:bounds]);
+ [_window setBackgroundColor:[UIColor whiteColor]];
+ [_window makeKeyAndVisible];
+
+ // Add a label with the app name.
+ UILabel* label = [[[UILabel alloc] initWithFrame:bounds] autorelease];
+ label.text = [[NSProcessInfo processInfo] processName];
+ label.textAlignment = NSTextAlignmentCenter;
+ [_window addSubview:label];
+
+ // An NSInternalInconsistencyException is thrown if the app doesn't have a
+ // root view controller. Set an empty one here.
+ [_window setRootViewController:[[[UIViewController alloc] init] autorelease]];
+
+ if ([self shouldRedirectOutputToFile])
+ [self redirectOutput];
+
+ // Queue up the test run.
+ if (!base::ShouldRunIOSUnittestsWithXCTest()) {
+ // When running in XCTest mode, XCTest will invoke |runGoogleTest| directly.
+ // Otherwise, schedule a call to |runTests|.
+ [self performSelector:@selector(runTests) withObject:nil afterDelay:0.1];
+ }
+
+ return YES;
+}
+
+// Returns true if the gtest output should be redirected to a file, then sent
+// to NSLog when complete. This redirection is used because gtest only writes
+// output to stdout, but results must be written to NSLog in order to show up in
+// the device log that is retrieved from the device by the host.
+- (BOOL)shouldRedirectOutputToFile {
+#if !TARGET_IPHONE_SIMULATOR
+ // Tests in XCTest mode don't need to redirect output to a file because the
+ // test result parser analyzes console output.
+ return !base::ShouldRunIOSUnittestsWithXCTest() &&
+ !base::debug::BeingDebugged();
+#else
+ return NO;
+#endif // TARGET_IPHONE_SIMULATOR
+}
+
+// Returns the path to the directory to store gtest output files.
+- (NSString*)outputPath {
+ NSArray* searchPath =
+ NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
+ NSUserDomainMask,
+ YES);
+ CHECK([searchPath count] > 0) << "Failed to get the Documents folder";
+ return [searchPath objectAtIndex:0];
+}
+
+// Returns the path to file that stdout is redirected to.
+- (NSString*)stdoutPath {
+ return [[self outputPath] stringByAppendingPathComponent:@"stdout.log"];
+}
+
+// Returns the path to file that stderr is redirected to.
+- (NSString*)stderrPath {
+ return [[self outputPath] stringByAppendingPathComponent:@"stderr.log"];
+}
+
+// Redirects stdout and stderr to files in the Documents folder in the app's
+// sandbox.
+- (void)redirectOutput {
+ freopen([[self stdoutPath] UTF8String], "w+", stdout);
+ freopen([[self stderrPath] UTF8String], "w+", stderr);
+}
+
+// Reads the redirected gtest output from a file and writes it to NSLog.
+- (void)writeOutputToNSLog {
+ // Close the redirected stdout and stderr files so that the content written to
+ // NSLog doesn't end up in these files.
+ fclose(stdout);
+ fclose(stderr);
+ for (NSString* path in @[ [self stdoutPath], [self stderrPath]]) {
+ NSString* content = [NSString stringWithContentsOfFile:path
+ encoding:NSUTF8StringEncoding
+ error:NULL];
+ NSArray* lines = [content componentsSeparatedByCharactersInSet:
+ [NSCharacterSet newlineCharacterSet]];
+
+ NSLog(@"Writing contents of %@ to NSLog", path);
+ for (NSString* line in lines) {
+ NSLog(@"%@", line);
+ }
+ }
+}
+
+- (BOOL)supportsRunningGoogleTests {
+ return base::ShouldRunIOSUnittestsWithXCTest();
+}
+
+- (int)runGoogleTests {
+ coverage_util::ConfigureCoverageReportPath();
+
+ int exitStatus = g_test_suite->Run();
+
+ if ([self shouldRedirectOutputToFile])
+ [self writeOutputToNSLog];
+
+ return exitStatus;
+}
+
+- (void)runTests {
+ DCHECK(!base::ShouldRunIOSUnittestsWithXCTest());
+
+ int exitStatus = [self runGoogleTests];
+
+ // If a test app is too fast, it will exit before Instruments has has a
+ // a chance to initialize and no test results will be seen.
+ [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
+ _window.reset();
+
+ // Use the hidden selector to try and cleanly take down the app (otherwise
+ // things can think the app crashed even on a zero exit status).
+ UIApplication* application = [UIApplication sharedApplication];
+ [application _terminateWithStatus:exitStatus];
+
+ exit(exitStatus);
+}
+
+@end
+
+namespace {
+
+std::unique_ptr<base::MessagePump> CreateMessagePumpForUIForTests() {
+ // A basic MessagePump will do quite nicely in tests.
+ return std::unique_ptr<base::MessagePump>(new base::MessagePumpCFRunLoop());
+}
+
+} // namespace
+
+namespace base {
+
+void InitIOSTestMessageLoop() {
+ MessagePump::OverrideMessagePumpForUIFactory(&CreateMessagePumpForUIForTests);
+}
+
+void InitIOSRunHook(TestSuite* suite, int argc, char* argv[]) {
+ g_test_suite = suite;
+ g_argc = argc;
+ g_argv = argv;
+}
+
+void RunTestsFromIOSApp() {
+ // When TestSuite::Run is invoked it calls RunTestsFromIOSApp(). On the first
+ // invocation, this method fires up an iOS app via UIApplicationMain. Since
+ // UIApplicationMain does not return until the app exits, control does not
+ // return to the initial TestSuite::Run invocation, so the app invokes
+ // TestSuite::Run a second time and since |ran_hook| is true at this point,
+ // this method is a no-op and control returns to TestSuite:Run so that test
+ // are executed. Once the app exits, RunTestsFromIOSApp calls exit() so that
+ // control is not returned to the initial invocation of TestSuite::Run.
+ static bool ran_hook = false;
+ if (!ran_hook) {
+ ran_hook = true;
+ @autoreleasepool {
+ int exit_status =
+ UIApplicationMain(g_argc, g_argv, nil, @"ChromeUnitTestDelegate");
+ exit(exit_status);
+ }
+ }
+}
+
+bool ShouldRunIOSUnittestsWithXCTest() {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableRunIOSUnittestsWithXCTest);
+}
+
+} // namespace base
diff --git a/chromium/base/test/test_switches.cc b/chromium/base/test/test_switches.cc
new file mode 100644
index 00000000000..ec022ced181
--- /dev/null
+++ b/chromium/base/test/test_switches.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_switches.h"
+
+// Flag to show the help message.
+const char switches::kHelpFlag[] = "help";
+
+// Flag to run all tests and the launcher in a single process. Useful for
+// debugging a specific test in a debugger.
+const char switches::kSingleProcessTests[] = "single-process-tests";
+
+// Maximum number of tests to run in a single batch.
+const char switches::kTestLauncherBatchLimit[] = "test-launcher-batch-limit";
+
+// Sets defaults desirable for the continuous integration bots, e.g. parallel
+// test execution and test retries.
+const char switches::kTestLauncherBotMode[] =
+ "test-launcher-bot-mode";
+
+// Makes it possible to debug the launcher itself. By default the launcher
+// automatically switches to single process mode when it detects presence
+// of debugger.
+const char switches::kTestLauncherDebugLauncher[] =
+ "test-launcher-debug-launcher";
+
+// Force running all requested tests and retries even if too many test errors
+// occur.
+const char switches::kTestLauncherForceRunBrokenTests[] =
+ "test-launcher-force-run-broken-tests";
+
+// List of paths to files (separated by ';') containing test filters (one
+// pattern per line).
+const char switches::kTestLauncherFilterFile[] = "test-launcher-filter-file";
+
+// Whether the test launcher should launch in "interactive mode", which disables
+// timeouts (and may have other effects for specific test types).
+const char switches::kTestLauncherInteractive[] = "test-launcher-interactive";
+
+// Number of parallel test launcher jobs.
+const char switches::kTestLauncherJobs[] = "test-launcher-jobs";
+
+// Path to list of compiled in tests.
+const char switches::kTestLauncherListTests[] = "test-launcher-list-tests";
+
+// Path to test results file in our custom test launcher format.
+const char switches::kTestLauncherOutput[] = "test-launcher-output";
+
+// These two flags has the same effect, but don't use them at the same time.
+// And isolated-script-test-launcher-retry-limit is preferred in the future.
+// Maximum number of times to retry a test after failure.
+const char switches::kTestLauncherRetryLimit[] = "test-launcher-retry-limit";
+const char switches::kIsolatedScriptTestLauncherRetryLimit[] =
+ "isolated-script-test-launcher-retry-limit";
+
+// Path to test results file with all the info from the test launcher.
+const char switches::kTestLauncherSummaryOutput[] =
+ "test-launcher-summary-output";
+
+// Causes the test launcher to print information about leaked files and/or
+// directories in child process's temporary directories.
+const char switches::kTestLauncherPrintTempLeaks[] =
+ "test-launcher-print-temp-leaks";
+
+// Flag controlling when test stdio is displayed as part of the launcher's
+// standard output.
+const char switches::kTestLauncherPrintTestStdio[] =
+ "test-launcher-print-test-stdio";
+
+// Print a writable path and exit (for internal use).
+const char switches::kTestLauncherPrintWritablePath[] =
+ "test-launcher-print-writable-path";
+
+// Index of the test shard to run, starting from 0 (first shard) to total shards
+// minus one (last shard).
+const char switches::kTestLauncherShardIndex[] =
+ "test-launcher-shard-index";
+
+// Limit of test part results in the output. Default limit is 10.
+// Negative value will completely disable limit.
+const char switches::kTestLauncherTestPartResultsLimit[] =
+ "test-launcher-test-part-results-limit";
+
+// Total number of shards. Must be the same for all shards.
+const char switches::kTestLauncherTotalShards[] =
+ "test-launcher-total-shards";
+
+// Time (in milliseconds) that the tests should wait before timing out.
+const char switches::kTestLauncherTimeout[] = "test-launcher-timeout";
+
+// Path where to save a trace of test launcher's execution.
+const char switches::kTestLauncherTrace[] = "test-launcher-trace";
+
+// TODO(phajdan.jr): Clean up the switch names.
+const char switches::kTestTinyTimeout[] = "test-tiny-timeout";
+const char switches::kUiTestActionTimeout[] = "ui-test-action-timeout";
+const char switches::kUiTestActionMaxTimeout[] = "ui-test-action-max-timeout";
+
+#if defined(OS_IOS)
+// If enabled, runs unittests using the XCTest test runner.
+const char switches::kEnableRunIOSUnittestsWithXCTest[] =
+ "enable-run-ios-unittests-with-xctest";
+#endif
diff --git a/chromium/base/test/test_switches.h b/chromium/base/test/test_switches.h
new file mode 100644
index 00000000000..9e2e627e407
--- /dev/null
+++ b/chromium/base/test/test_switches.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SWITCHES_H_
+#define BASE_TEST_TEST_SWITCHES_H_
+
+#include "build/build_config.h"
+
+namespace switches {
+
+// All switches in alphabetical order. The switches should be documented
+// alongside the definition of their values in the .cc file.
+extern const char kHelpFlag[];
+extern const char kSingleProcessTests[];
+extern const char kTestLauncherBatchLimit[];
+extern const char kTestLauncherBotMode[];
+extern const char kTestLauncherDebugLauncher[];
+extern const char kTestLauncherForceRunBrokenTests[];
+extern const char kTestLauncherFilterFile[];
+extern const char kTestLauncherInteractive[];
+extern const char kTestLauncherJobs[];
+extern const char kTestLauncherListTests[];
+extern const char kTestLauncherOutput[];
+extern const char kTestLauncherRetryLimit[];
+extern const char kIsolatedScriptTestLauncherRetryLimit[];
+extern const char kTestLauncherSummaryOutput[];
+extern const char kTestLauncherPrintTempLeaks[];
+extern const char kTestLauncherPrintTestStdio[];
+extern const char kTestLauncherPrintWritablePath[];
+extern const char kTestLauncherShardIndex[];
+extern const char kTestLauncherTestPartResultsLimit[];
+extern const char kTestLauncherTotalShards[];
+extern const char kTestLauncherTimeout[];
+extern const char kTestLauncherTrace[];
+extern const char kTestTinyTimeout[];
+extern const char kUiTestActionTimeout[];
+extern const char kUiTestActionMaxTimeout[];
+
+#if defined(OS_IOS)
+extern const char kEnableRunIOSUnittestsWithXCTest[];
+#endif
+
+} // namespace switches
+
+#endif // BASE_TEST_TEST_SWITCHES_H_
diff --git a/chromium/base/test/test_timeouts.cc b/chromium/base/test/test_timeouts.cc
new file mode 100644
index 00000000000..e77f17569c0
--- /dev/null
+++ b/chromium/base/test/test_timeouts.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_timeouts.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/clang_profiling_buildflags.h"
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/test_switches.h"
+#include "build/build_config.h"
+
+namespace {
+
+// Sets value to the greatest of:
+// 1) value's current value multiplied by kTimeoutMultiplier (assuming
+// InitializeTimeout is called only once per value).
+// 2) min_value.
+// 3) the numerical value given by switch_name on the command line multiplied
+// by kTimeoutMultiplier.
+void InitializeTimeout(const char* switch_name, int min_value, int* value) {
+ DCHECK(value);
+ int command_line_timeout = 0;
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) {
+ std::string string_value(base::CommandLine::ForCurrentProcess()->
+ GetSwitchValueASCII(switch_name));
+ if (!base::StringToInt(string_value, &command_line_timeout)) {
+ LOG(FATAL) << "Timeout value \"" << string_value << "\" was parsed as "
+ << command_line_timeout;
+ }
+ }
+
+#if defined(MEMORY_SANITIZER)
+ // ASan/TSan/MSan instrument each memory access. This may slow the execution
+ // down significantly.
+ // For MSan the slowdown depends heavily on the value of msan_track_origins
+ // build flag. The multiplier below corresponds to msan_track_origins = 1.
+#if defined(OS_CHROMEOS)
+ // A handful of tests on ChromeOS run *very* close to the 6x limit used
+ // else where, so it's bumped to 7x.
+ constexpr int kTimeoutMultiplier = 7;
+#else
+ constexpr int kTimeoutMultiplier = 6;
+#endif
+#elif defined(ADDRESS_SANITIZER) && defined(OS_WIN)
+ // ASan/Win has not been optimized yet, give it a higher
+ // timeout multiplier. See http://crbug.com/412471
+ constexpr int kTimeoutMultiplier = 3;
+#elif defined(ADDRESS_SANITIZER) && defined(OS_CHROMEOS)
+ // A number of tests on ChromeOS run very close to the 2x limit, so ChromeOS
+ // gets 3x.
+ constexpr int kTimeoutMultiplier = 3;
+#elif defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER)
+ constexpr int kTimeoutMultiplier = 2;
+#elif BUILDFLAG(CLANG_PROFILING)
+ // On coverage build, tests run 3x slower.
+ constexpr int kTimeoutMultiplier = 3;
+#elif !defined(NDEBUG) && defined(OS_CHROMEOS)
+ // TODO(crbug.com/1058022): reduce the multiplier back to 2x.
+ // A number of tests on ChromeOS run very close to the base limit, so ChromeOS
+ // gets 3x.
+ constexpr int kTimeoutMultiplier = 3;
+#else
+ constexpr int kTimeoutMultiplier = 1;
+#endif
+
+ *value = std::max(std::max(*value, command_line_timeout) * kTimeoutMultiplier,
+ min_value);
+}
+
+} // namespace
+
+// static
+bool TestTimeouts::initialized_ = false;
+
+// The timeout values should increase in the order they appear in this block.
+// static
+int TestTimeouts::tiny_timeout_ms_ = 100;
+int TestTimeouts::action_timeout_ms_ = 10000;
+int TestTimeouts::action_max_timeout_ms_ = 30000;
+int TestTimeouts::test_launcher_timeout_ms_ = 45000;
+
+// static
+void TestTimeouts::Initialize() {
+ DCHECK(!initialized_);
+ initialized_ = true;
+
+ const bool being_debugged = base::debug::BeingDebugged();
+ if (being_debugged) {
+ fprintf(stdout,
+ "Detected presence of a debugger, running without test timeouts.\n");
+ }
+
+ // Note that these timeouts MUST be initialized in the correct order as
+ // per the CHECKS below.
+
+ InitializeTimeout(switches::kTestTinyTimeout, 0, &tiny_timeout_ms_);
+
+ // All timeouts other than the "tiny" one should be set to very large values
+ // when in a debugger or when run interactively, so that tests will not get
+ // auto-terminated. By setting the UI test action timeout to at least this
+ // value, we guarantee the subsequent timeouts will be this large also.
+ // Setting the "tiny" timeout to a large value as well would make some tests
+ // hang (because it's used as a task-posting delay). In particular this
+ // causes problems for some iOS device tests, which are always run inside a
+ // debugger (thus BeingDebugged() is true even on the bots).
+ int min_ui_test_action_timeout = tiny_timeout_ms_;
+ if (being_debugged || base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kTestLauncherInteractive)) {
+ constexpr int kVeryLargeTimeoutMs = 100'000'000;
+ min_ui_test_action_timeout = kVeryLargeTimeoutMs;
+ }
+
+ InitializeTimeout(switches::kUiTestActionTimeout, min_ui_test_action_timeout,
+ &action_timeout_ms_);
+ InitializeTimeout(switches::kUiTestActionMaxTimeout, action_timeout_ms_,
+ &action_max_timeout_ms_);
+
+ // Test launcher timeout is independent from anything above action timeout.
+ InitializeTimeout(switches::kTestLauncherTimeout, action_timeout_ms_,
+ &test_launcher_timeout_ms_);
+
+ // The timeout values should be increasing in the right order.
+ CHECK_LE(tiny_timeout_ms_, action_timeout_ms_);
+ CHECK_LE(action_timeout_ms_, action_max_timeout_ms_);
+ CHECK_LE(action_timeout_ms_, test_launcher_timeout_ms_);
+}
diff --git a/chromium/base/test/test_timeouts.h b/chromium/base/test/test_timeouts.h
new file mode 100644
index 00000000000..1bdda2a157b
--- /dev/null
+++ b/chromium/base/test/test_timeouts.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_TIMEOUTS_H_
+#define BASE_TEST_TEST_TIMEOUTS_H_
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+
+// Returns common timeouts to use in tests. Makes it possible to adjust
+// the timeouts for different environments (like TSan).
+class TestTimeouts {
+ public:
+ // Initializes the timeouts. Non thread-safe. Should be called exactly once
+ // by the test suite.
+ static void Initialize();
+
+ // Timeout for actions that are expected to finish "almost instantly". This
+ // is used in various tests to post delayed tasks and usually functions more
+ // like a delay value than a timeout.
+ static base::TimeDelta tiny_timeout() {
+ DCHECK(initialized_);
+ return base::TimeDelta::FromMilliseconds(tiny_timeout_ms_);
+ }
+
+ // Timeout to wait for something to happen. If you are not sure
+ // which timeout to use, this is the one you want.
+ static base::TimeDelta action_timeout() {
+ DCHECK(initialized_);
+ return base::TimeDelta::FromMilliseconds(action_timeout_ms_);
+ }
+
+ // Timeout longer than the above, suitable to wait on success conditions which
+ // can take a while to achieve but still should expire on failure before
+ // |test_launcher_timeout()| terminates the process. Note that
+ // test_launcher_timeout() can be reached nonetheless when multiple such
+ // actions are compounded in the same test.
+ static base::TimeDelta action_max_timeout() {
+ DCHECK(initialized_);
+ return base::TimeDelta::FromMilliseconds(action_max_timeout_ms_);
+ }
+
+ // Timeout for a single test launched used built-in test launcher.
+ // Do not use outside of the test launcher.
+ static base::TimeDelta test_launcher_timeout() {
+ DCHECK(initialized_);
+ return base::TimeDelta::FromMilliseconds(test_launcher_timeout_ms_);
+ }
+
+ private:
+ static bool initialized_;
+
+ static int tiny_timeout_ms_;
+ static int action_timeout_ms_;
+ static int action_max_timeout_ms_;
+ static int test_launcher_timeout_ms_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(TestTimeouts);
+};
+
+#endif // BASE_TEST_TEST_TIMEOUTS_H_
diff --git a/chromium/base/test/test_waitable_event.cc b/chromium/base/test/test_waitable_event.cc
new file mode 100644
index 00000000000..09f5bb66e0e
--- /dev/null
+++ b/chromium/base/test/test_waitable_event.cc
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_waitable_event.h"
+
+#include <utility>
+
+namespace base {
+
+TestWaitableEvent::TestWaitableEvent(ResetPolicy reset_policy,
+ InitialState initial_state)
+ : WaitableEvent(reset_policy, initial_state) {
+ // Pretending this is only used while idle ensures this WaitableEvent is not
+ // instantiating a ScopedBlockingCallWithBaseSyncPrimitives in Wait(). In
+ // other words, test logic is considered "idle" work (not part of the tested
+ // logic).
+ declare_only_used_while_idle();
+}
+
+#if defined(OS_WIN)
+TestWaitableEvent::TestWaitableEvent(win::ScopedHandle event_handle)
+ : WaitableEvent(std::move(event_handle)) {
+ declare_only_used_while_idle();
+}
+#endif
+
+} // namespace base
diff --git a/chromium/base/test/test_waitable_event.h b/chromium/base/test/test_waitable_event.h
new file mode 100644
index 00000000000..ff3bc21529d
--- /dev/null
+++ b/chromium/base/test/test_waitable_event.h
@@ -0,0 +1,40 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_WAITABLE_EVENT_H_
+#define BASE_TEST_TEST_WAITABLE_EVENT_H_
+
+#include "base/synchronization/waitable_event.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#endif
+
+namespace base {
+
+// A WaitableEvent for use in tests, it has the same API as WaitableEvent with
+// the following two distinctions:
+// 1) ScopedAllowBaseSyncPrimitivesForTesting is not required to block on it.
+// 2) It doesn't instantiate a ScopedBlockingCallWithBaseSyncPrimitives in
+// Wait() (important in some //base tests that are thrown off when the
+// WaitableEvents used to drive the test add additional ScopedBlockingCalls
+// to the mix of monitored calls).
+class TestWaitableEvent : public WaitableEvent {
+ public:
+ TestWaitableEvent(ResetPolicy reset_policy = ResetPolicy::MANUAL,
+ InitialState initial_state = InitialState::NOT_SIGNALED);
+
+#if defined(OS_WIN)
+ explicit TestWaitableEvent(win::ScopedHandle event_handle);
+#endif
+};
+
+static_assert(sizeof(TestWaitableEvent) == sizeof(WaitableEvent),
+ "WaitableEvent is non-virtual, TestWaitableEvent must be usable "
+ "interchangeably.");
+
+} // namespace base
+
+#endif // BASE_TEST_TEST_WAITABLE_EVENT_H_
diff --git a/chromium/base/test/test_waitable_event_unittest.cc b/chromium/base/test/test_waitable_event_unittest.cc
new file mode 100644
index 00000000000..8e344655916
--- /dev/null
+++ b/chromium/base/test/test_waitable_event_unittest.cc
@@ -0,0 +1,66 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_waitable_event.h"
+
+#include "base/bind.h"
+#include "base/test/task_environment.h"
+#include "base/threading/scoped_blocking_call_internal.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class NoInvokeBlockingObserver : public internal::BlockingObserver {
+ public:
+ void BlockingStarted(BlockingType blocking_type) override { ADD_FAILURE(); }
+ void BlockingTypeUpgraded() override { ADD_FAILURE(); }
+ void BlockingEnded() override { ADD_FAILURE(); }
+};
+
+TEST(TestWaitableEvent, NoBlockingCall) {
+ test::TaskEnvironment task_environment;
+
+ NoInvokeBlockingObserver test_observer;
+ internal::SetBlockingObserverForCurrentThread(&test_observer);
+
+ TestWaitableEvent test_waitable_event;
+ ThreadPool::PostTask(
+ FROM_HERE, {},
+ BindOnce(&WaitableEvent::Signal, Unretained(&test_waitable_event)));
+ test_waitable_event.Wait();
+
+ internal::ClearBlockingObserverForCurrentThread();
+}
+
+TEST(TestWaitableEvent, WaitingInPoolDoesntRequireAllowance) {
+ test::TaskEnvironment task_environment;
+
+ TestWaitableEvent test_waitable_event;
+ // MayBlock()/WithBaseSyncPrimitives()/ScopedAllowBaseSyncPrimitivesForTesting
+ // are required to Wait() on a TestWaitableEvent.
+ ThreadPool::PostTask(
+ FROM_HERE, {},
+ BindOnce(&WaitableEvent::Wait, Unretained(&test_waitable_event)));
+ test_waitable_event.Signal();
+
+ task_environment.RunUntilIdle();
+}
+
+// Binding &WaitableEvent::Signal or &TestWaitableEvent::Signal is equivalent.
+TEST(TestWaitableEvent, CanBindEitherType) {
+ test::TaskEnvironment task_environment;
+ TestWaitableEvent test_waitable_event(WaitableEvent::ResetPolicy::AUTOMATIC);
+
+ ThreadPool::PostTask(
+ FROM_HERE, {},
+ BindOnce(&WaitableEvent::Signal, Unretained(&test_waitable_event)));
+ test_waitable_event.Wait();
+
+ ThreadPool::PostTask(
+ FROM_HERE, {},
+ BindOnce(&TestWaitableEvent::Signal, Unretained(&test_waitable_event)));
+ test_waitable_event.Wait();
+}
+
+} // namespace base
diff --git a/chromium/base/test/thread_pool_test_helpers_android.cc b/chromium/base/test/thread_pool_test_helpers_android.cc
new file mode 100644
index 00000000000..f2590a42c4f
--- /dev/null
+++ b/chromium/base/test/thread_pool_test_helpers_android.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/test/test_support_jni_headers/ThreadPoolTestHelpers_jni.h"
+
+namespace base {
+
+// ThreadPoolTestHelpers is a friend of ThreadPoolInstance which grants access
+// to SetCanRun().
+class ThreadPoolTestHelpers {
+ public:
+ // Enables/disables an execution fence that prevents tasks from running.
+ static void BeginFenceForTesting();
+ static void EndFenceForTesting();
+};
+
+// static
+void ThreadPoolTestHelpers::BeginFenceForTesting() {
+ ThreadPoolInstance::Get()->BeginFence();
+}
+
+// static
+void ThreadPoolTestHelpers::EndFenceForTesting() {
+ ThreadPoolInstance::Get()->EndFence();
+}
+
+} // namespace base
+
+void JNI_ThreadPoolTestHelpers_EnableThreadPoolExecutionForTesting(
+ JNIEnv* env) {
+ base::ThreadPoolTestHelpers::EndFenceForTesting();
+}
+
+void JNI_ThreadPoolTestHelpers_DisableThreadPoolExecutionForTesting(
+ JNIEnv* env) {
+ base::ThreadPoolTestHelpers::BeginFenceForTesting();
+} \ No newline at end of file
diff --git a/chromium/base/test/thread_test_helper.cc b/chromium/base/test/thread_test_helper.cc
new file mode 100644
index 00000000000..03d6b2d6f3d
--- /dev/null
+++ b/chromium/base/test/thread_test_helper.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/thread_test_helper.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+ThreadTestHelper::ThreadTestHelper(
+ scoped_refptr<SequencedTaskRunner> target_sequence)
+ : test_result_(false),
+ target_sequence_(std::move(target_sequence)),
+ done_event_(WaitableEvent::ResetPolicy::AUTOMATIC,
+ WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+bool ThreadTestHelper::Run() {
+ if (!target_sequence_->PostTask(
+ FROM_HERE, base::BindOnce(&ThreadTestHelper::RunOnSequence, this))) {
+ return false;
+ }
+ base::ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
+ done_event_.Wait();
+ return test_result_;
+}
+
+void ThreadTestHelper::RunTest() { set_test_result(true); }
+
+ThreadTestHelper::~ThreadTestHelper() = default;
+
+void ThreadTestHelper::RunOnSequence() {
+ RunTest();
+ done_event_.Signal();
+}
+
+} // namespace base
diff --git a/chromium/base/test/thread_test_helper.h b/chromium/base/test/thread_test_helper.h
new file mode 100644
index 00000000000..935e7efc6b9
--- /dev/null
+++ b/chromium/base/test/thread_test_helper.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_THREAD_TEST_HELPER_H_
+#define BASE_TEST_THREAD_TEST_HELPER_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+
+// Helper class that executes code on a given target sequence/thread while
+// blocking on the invoking sequence/thread. To use, derive from this class and
+// overwrite RunTest. An alternative use of this class is to use it directly. It
+// will then block until all pending tasks on a given sequence/thread have been
+// executed.
+class ThreadTestHelper : public RefCountedThreadSafe<ThreadTestHelper> {
+ public:
+ explicit ThreadTestHelper(scoped_refptr<SequencedTaskRunner> target_sequence);
+
+ // True if RunTest() was successfully executed on the target sequence.
+ bool Run() WARN_UNUSED_RESULT;
+
+ virtual void RunTest();
+
+ protected:
+ friend class RefCountedThreadSafe<ThreadTestHelper>;
+
+ virtual ~ThreadTestHelper();
+
+ // Use this method to store the result of RunTest().
+ void set_test_result(bool test_result) { test_result_ = test_result; }
+
+ private:
+ void RunOnSequence();
+
+ bool test_result_;
+ scoped_refptr<SequencedTaskRunner> target_sequence_;
+ WaitableEvent done_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadTestHelper);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_THREAD_TEST_HELPER_H_
diff --git a/chromium/base/test/trace_event_analyzer.cc b/chromium/base/test/trace_event_analyzer.cc
new file mode 100644
index 00000000000..78a6b9b4cae
--- /dev/null
+++ b/chromium/base/test/trace_event_analyzer.cc
@@ -0,0 +1,1077 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/trace_event_analyzer.h"
+
+#include <math.h>
+
+#include <algorithm>
+#include <set>
+
+#include "base/bind.h"
+#include "base/json/json_reader.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/run_loop.h"
+#include "base/strings/pattern.h"
+#include "base/trace_event/trace_buffer.h"
+#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_log.h"
+#include "base/values.h"
+
+namespace {
+void OnTraceDataCollected(base::OnceClosure quit_closure,
+ base::trace_event::TraceResultBuffer* buffer,
+ const scoped_refptr<base::RefCountedString>& json,
+ bool has_more_events) {
+ buffer->AddFragment(json->data());
+ if (!has_more_events)
+ std::move(quit_closure).Run();
+}
+} // namespace
+
+namespace trace_analyzer {
+
+// TraceEvent
+
+TraceEvent::TraceEvent()
+ : thread(0, 0),
+ timestamp(0),
+ duration(0),
+ phase(TRACE_EVENT_PHASE_BEGIN),
+ other_event(nullptr) {}
+
+TraceEvent::TraceEvent(TraceEvent&& other) = default;
+
+TraceEvent::~TraceEvent() = default;
+
+TraceEvent& TraceEvent::operator=(TraceEvent&& rhs) = default;
+
+bool TraceEvent::SetFromJSON(const base::Value* event_value) {
+ if (event_value->type() != base::Value::Type::DICTIONARY) {
+ LOG(ERROR) << "Value must be Type::DICTIONARY";
+ return false;
+ }
+ const base::DictionaryValue* dictionary =
+ static_cast<const base::DictionaryValue*>(event_value);
+
+ std::string phase_str;
+ const base::DictionaryValue* args = nullptr;
+
+ if (!dictionary->GetString("ph", &phase_str)) {
+ LOG(ERROR) << "ph is missing from TraceEvent JSON";
+ return false;
+ }
+
+ phase = *phase_str.data();
+
+ bool may_have_duration = (phase == TRACE_EVENT_PHASE_COMPLETE);
+ bool require_origin = (phase != TRACE_EVENT_PHASE_METADATA);
+ bool require_id = (phase == TRACE_EVENT_PHASE_ASYNC_BEGIN ||
+ phase == TRACE_EVENT_PHASE_ASYNC_STEP_INTO ||
+ phase == TRACE_EVENT_PHASE_ASYNC_STEP_PAST ||
+ phase == TRACE_EVENT_PHASE_MEMORY_DUMP ||
+ phase == TRACE_EVENT_PHASE_ENTER_CONTEXT ||
+ phase == TRACE_EVENT_PHASE_LEAVE_CONTEXT ||
+ phase == TRACE_EVENT_PHASE_CREATE_OBJECT ||
+ phase == TRACE_EVENT_PHASE_DELETE_OBJECT ||
+ phase == TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ||
+ phase == TRACE_EVENT_PHASE_ASYNC_END);
+
+ if (require_origin && !dictionary->GetInteger("pid", &thread.process_id)) {
+ LOG(ERROR) << "pid is missing from TraceEvent JSON";
+ return false;
+ }
+ if (require_origin && !dictionary->GetInteger("tid", &thread.thread_id)) {
+ LOG(ERROR) << "tid is missing from TraceEvent JSON";
+ return false;
+ }
+ if (require_origin && !dictionary->GetDouble("ts", &timestamp)) {
+ LOG(ERROR) << "ts is missing from TraceEvent JSON";
+ return false;
+ }
+ if (may_have_duration) {
+ dictionary->GetDouble("dur", &duration);
+ }
+ if (!dictionary->GetString("cat", &category)) {
+ LOG(ERROR) << "cat is missing from TraceEvent JSON";
+ return false;
+ }
+ if (!dictionary->GetString("name", &name)) {
+ LOG(ERROR) << "name is missing from TraceEvent JSON";
+ return false;
+ }
+ if (!dictionary->GetDictionary("args", &args)) {
+ std::string stripped_args;
+ // If argument filter is enabled, the arguments field contains a string
+ // value.
+ if (!dictionary->GetString("args", &stripped_args) ||
+ stripped_args != "__stripped__") {
+ LOG(ERROR) << "args is missing from TraceEvent JSON";
+ return false;
+ }
+ }
+ if (require_id && !dictionary->GetString("id", &id) &&
+ !dictionary->FindKey("id2")) {
+ LOG(ERROR)
+ << "id/id2 is missing from ASYNC_BEGIN/ASYNC_END TraceEvent JSON";
+ return false;
+ }
+
+ dictionary->GetDouble("tdur", &thread_duration);
+ dictionary->GetDouble("tts", &thread_timestamp);
+ dictionary->GetString("scope", &scope);
+ dictionary->GetString("bind_id", &bind_id);
+ dictionary->GetBoolean("flow_out", &flow_out);
+ dictionary->GetBoolean("flow_in", &flow_in);
+
+ const base::DictionaryValue* id2;
+ if (dictionary->GetDictionary("id2", &id2)) {
+ id2->GetString("global", &global_id2);
+ id2->GetString("local", &local_id2);
+ }
+
+ // For each argument, copy the type and create a trace_analyzer::TraceValue.
+ if (args) {
+ for (base::DictionaryValue::Iterator it(*args); !it.IsAtEnd();
+ it.Advance()) {
+ std::string str;
+ bool boolean = false;
+ int int_num = 0;
+ double double_num = 0.0;
+ if (it.value().GetAsString(&str)) {
+ arg_strings[it.key()] = str;
+ } else if (it.value().GetAsInteger(&int_num)) {
+ arg_numbers[it.key()] = static_cast<double>(int_num);
+ } else if (it.value().GetAsBoolean(&boolean)) {
+ arg_numbers[it.key()] = static_cast<double>(boolean ? 1 : 0);
+ } else if (it.value().GetAsDouble(&double_num)) {
+ arg_numbers[it.key()] = double_num;
+ }
+ // Record all arguments as values.
+ arg_values[it.key()] = it.value().CreateDeepCopy();
+ }
+ }
+
+ return true;
+}
+
+double TraceEvent::GetAbsTimeToOtherEvent() const {
+ return fabs(other_event->timestamp - timestamp);
+}
+
+bool TraceEvent::GetArgAsString(const std::string& name,
+ std::string* arg) const {
+ const auto it = arg_strings.find(name);
+ if (it != arg_strings.end()) {
+ *arg = it->second;
+ return true;
+ }
+ return false;
+}
+
+bool TraceEvent::GetArgAsNumber(const std::string& name,
+ double* arg) const {
+ const auto it = arg_numbers.find(name);
+ if (it != arg_numbers.end()) {
+ *arg = it->second;
+ return true;
+ }
+ return false;
+}
+
+bool TraceEvent::GetArgAsValue(const std::string& name,
+ std::unique_ptr<base::Value>* arg) const {
+ const auto it = arg_values.find(name);
+ if (it != arg_values.end()) {
+ *arg = it->second->CreateDeepCopy();
+ return true;
+ }
+ return false;
+}
+
+bool TraceEvent::HasStringArg(const std::string& name) const {
+ return (arg_strings.find(name) != arg_strings.end());
+}
+
+bool TraceEvent::HasNumberArg(const std::string& name) const {
+ return (arg_numbers.find(name) != arg_numbers.end());
+}
+
+bool TraceEvent::HasArg(const std::string& name) const {
+ return (arg_values.find(name) != arg_values.end());
+}
+
+std::string TraceEvent::GetKnownArgAsString(const std::string& name) const {
+ std::string arg_string;
+ bool result = GetArgAsString(name, &arg_string);
+ DCHECK(result);
+ return arg_string;
+}
+
+double TraceEvent::GetKnownArgAsDouble(const std::string& name) const {
+ double arg_double = 0;
+ bool result = GetArgAsNumber(name, &arg_double);
+ DCHECK(result);
+ return arg_double;
+}
+
+int TraceEvent::GetKnownArgAsInt(const std::string& name) const {
+ double arg_double = 0;
+ bool result = GetArgAsNumber(name, &arg_double);
+ DCHECK(result);
+ return static_cast<int>(arg_double);
+}
+
+bool TraceEvent::GetKnownArgAsBool(const std::string& name) const {
+ double arg_double = 0;
+ bool result = GetArgAsNumber(name, &arg_double);
+ DCHECK(result);
+ return (arg_double != 0.0);
+}
+
+std::unique_ptr<base::Value> TraceEvent::GetKnownArgAsValue(
+ const std::string& name) const {
+ std::unique_ptr<base::Value> arg_value;
+ bool result = GetArgAsValue(name, &arg_value);
+ DCHECK(result);
+ return arg_value;
+}
+
+// QueryNode
+
+QueryNode::QueryNode(const Query& query) : query_(query) {
+}
+
+QueryNode::~QueryNode() = default;
+
+// Query
+
+Query::Query(TraceEventMember member)
+ : type_(QUERY_EVENT_MEMBER),
+ operator_(OP_INVALID),
+ member_(member),
+ number_(0),
+ is_pattern_(false) {
+}
+
+Query::Query(TraceEventMember member, const std::string& arg_name)
+ : type_(QUERY_EVENT_MEMBER),
+ operator_(OP_INVALID),
+ member_(member),
+ number_(0),
+ string_(arg_name),
+ is_pattern_(false) {
+}
+
+Query::Query(const Query& query) = default;
+
+Query::~Query() = default;
+
+Query Query::String(const std::string& str) {
+ return Query(str);
+}
+
+Query Query::Double(double num) {
+ return Query(num);
+}
+
+Query Query::Int(int32_t num) {
+ return Query(static_cast<double>(num));
+}
+
+Query Query::Uint(uint32_t num) {
+ return Query(static_cast<double>(num));
+}
+
+Query Query::Bool(bool boolean) {
+ return Query(boolean ? 1.0 : 0.0);
+}
+
+Query Query::Phase(char phase) {
+ return Query(static_cast<double>(phase));
+}
+
+Query Query::Pattern(const std::string& pattern) {
+ Query query(pattern);
+ query.is_pattern_ = true;
+ return query;
+}
+
+bool Query::Evaluate(const TraceEvent& event) const {
+ // First check for values that can convert to bool.
+
+ // double is true if != 0:
+ double bool_value = 0.0;
+ bool is_bool = GetAsDouble(event, &bool_value);
+ if (is_bool)
+ return (bool_value != 0.0);
+
+ // string is true if it is non-empty:
+ std::string str_value;
+ bool is_str = GetAsString(event, &str_value);
+ if (is_str)
+ return !str_value.empty();
+
+ DCHECK_EQ(QUERY_BOOLEAN_OPERATOR, type_)
+ << "Invalid query: missing boolean expression";
+ DCHECK(left_.get());
+ DCHECK(right_.get() || is_unary_operator());
+
+ if (is_comparison_operator()) {
+ DCHECK(left().is_value() && right().is_value())
+ << "Invalid query: comparison operator used between event member and "
+ "value.";
+ bool compare_result = false;
+ if (CompareAsDouble(event, &compare_result))
+ return compare_result;
+ if (CompareAsString(event, &compare_result))
+ return compare_result;
+ return false;
+ }
+ // It's a logical operator.
+ switch (operator_) {
+ case OP_AND:
+ return left().Evaluate(event) && right().Evaluate(event);
+ case OP_OR:
+ return left().Evaluate(event) || right().Evaluate(event);
+ case OP_NOT:
+ return !left().Evaluate(event);
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+bool Query::CompareAsDouble(const TraceEvent& event, bool* result) const {
+ double lhs, rhs;
+ if (!left().GetAsDouble(event, &lhs) || !right().GetAsDouble(event, &rhs))
+ return false;
+ switch (operator_) {
+ case OP_EQ:
+ *result = (lhs == rhs);
+ return true;
+ case OP_NE:
+ *result = (lhs != rhs);
+ return true;
+ case OP_LT:
+ *result = (lhs < rhs);
+ return true;
+ case OP_LE:
+ *result = (lhs <= rhs);
+ return true;
+ case OP_GT:
+ *result = (lhs > rhs);
+ return true;
+ case OP_GE:
+ *result = (lhs >= rhs);
+ return true;
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+bool Query::CompareAsString(const TraceEvent& event, bool* result) const {
+ std::string lhs, rhs;
+ if (!left().GetAsString(event, &lhs) || !right().GetAsString(event, &rhs))
+ return false;
+ switch (operator_) {
+ case OP_EQ:
+ if (right().is_pattern_)
+ *result = base::MatchPattern(lhs, rhs);
+ else if (left().is_pattern_)
+ *result = base::MatchPattern(rhs, lhs);
+ else
+ *result = (lhs == rhs);
+ return true;
+ case OP_NE:
+ if (right().is_pattern_)
+ *result = !base::MatchPattern(lhs, rhs);
+ else if (left().is_pattern_)
+ *result = !base::MatchPattern(rhs, lhs);
+ else
+ *result = (lhs != rhs);
+ return true;
+ case OP_LT:
+ *result = (lhs < rhs);
+ return true;
+ case OP_LE:
+ *result = (lhs <= rhs);
+ return true;
+ case OP_GT:
+ *result = (lhs > rhs);
+ return true;
+ case OP_GE:
+ *result = (lhs >= rhs);
+ return true;
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+bool Query::EvaluateArithmeticOperator(const TraceEvent& event,
+ double* num) const {
+ DCHECK_EQ(QUERY_ARITHMETIC_OPERATOR, type_);
+ DCHECK(left_.get());
+ DCHECK(right_.get() || is_unary_operator());
+
+ double lhs = 0, rhs = 0;
+ if (!left().GetAsDouble(event, &lhs))
+ return false;
+ if (!is_unary_operator() && !right().GetAsDouble(event, &rhs))
+ return false;
+
+ switch (operator_) {
+ case OP_ADD:
+ *num = lhs + rhs;
+ return true;
+ case OP_SUB:
+ *num = lhs - rhs;
+ return true;
+ case OP_MUL:
+ *num = lhs * rhs;
+ return true;
+ case OP_DIV:
+ *num = lhs / rhs;
+ return true;
+ case OP_MOD:
+ *num = static_cast<double>(static_cast<int64_t>(lhs) %
+ static_cast<int64_t>(rhs));
+ return true;
+ case OP_NEGATE:
+ *num = -lhs;
+ return true;
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+bool Query::GetAsDouble(const TraceEvent& event, double* num) const {
+ switch (type_) {
+ case QUERY_ARITHMETIC_OPERATOR:
+ return EvaluateArithmeticOperator(event, num);
+ case QUERY_EVENT_MEMBER:
+ return GetMemberValueAsDouble(event, num);
+ case QUERY_NUMBER:
+ *num = number_;
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Query::GetAsString(const TraceEvent& event, std::string* str) const {
+ switch (type_) {
+ case QUERY_EVENT_MEMBER:
+ return GetMemberValueAsString(event, str);
+ case QUERY_STRING:
+ *str = string_;
+ return true;
+ default:
+ return false;
+ }
+}
+
+const TraceEvent* Query::SelectTargetEvent(const TraceEvent* event,
+ TraceEventMember member) {
+ if (member >= OTHER_FIRST_MEMBER && member <= OTHER_LAST_MEMBER)
+ return event->other_event;
+ if (member >= PREV_FIRST_MEMBER && member <= PREV_LAST_MEMBER)
+ return event->prev_event;
+ return event;
+}
+
+bool Query::GetMemberValueAsDouble(const TraceEvent& event,
+ double* num) const {
+ DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
+
+ // This could be a request for a member of |event| or a member of |event|'s
+ // associated previous or next event. Store the target event in the_event:
+ const TraceEvent* the_event = SelectTargetEvent(&event, member_);
+
+ // Request for member of associated event, but there is no associated event.
+ if (!the_event)
+ return false;
+
+ switch (member_) {
+ case EVENT_PID:
+ case OTHER_PID:
+ case PREV_PID:
+ *num = static_cast<double>(the_event->thread.process_id);
+ return true;
+ case EVENT_TID:
+ case OTHER_TID:
+ case PREV_TID:
+ *num = static_cast<double>(the_event->thread.thread_id);
+ return true;
+ case EVENT_TIME:
+ case OTHER_TIME:
+ case PREV_TIME:
+ *num = the_event->timestamp;
+ return true;
+ case EVENT_DURATION:
+ if (!the_event->has_other_event())
+ return false;
+ *num = the_event->GetAbsTimeToOtherEvent();
+ return true;
+ case EVENT_COMPLETE_DURATION:
+ if (the_event->phase != TRACE_EVENT_PHASE_COMPLETE)
+ return false;
+ *num = the_event->duration;
+ return true;
+ case EVENT_PHASE:
+ case OTHER_PHASE:
+ case PREV_PHASE:
+ *num = static_cast<double>(the_event->phase);
+ return true;
+ case EVENT_HAS_STRING_ARG:
+ case OTHER_HAS_STRING_ARG:
+ case PREV_HAS_STRING_ARG:
+ *num = (the_event->HasStringArg(string_) ? 1.0 : 0.0);
+ return true;
+ case EVENT_HAS_NUMBER_ARG:
+ case OTHER_HAS_NUMBER_ARG:
+ case PREV_HAS_NUMBER_ARG:
+ *num = (the_event->HasNumberArg(string_) ? 1.0 : 0.0);
+ return true;
+ case EVENT_ARG:
+ case OTHER_ARG:
+ case PREV_ARG: {
+ // Search for the argument name and return its value if found.
+ auto num_i = the_event->arg_numbers.find(string_);
+ if (num_i == the_event->arg_numbers.end())
+ return false;
+ *num = num_i->second;
+ return true;
+ }
+ case EVENT_HAS_OTHER:
+ // return 1.0 (true) if the other event exists
+ *num = event.other_event ? 1.0 : 0.0;
+ return true;
+ case EVENT_HAS_PREV:
+ *num = event.prev_event ? 1.0 : 0.0;
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Query::GetMemberValueAsString(const TraceEvent& event,
+ std::string* str) const {
+ DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
+
+ // This could be a request for a member of |event| or a member of |event|'s
+ // associated previous or next event. Store the target event in the_event:
+ const TraceEvent* the_event = SelectTargetEvent(&event, member_);
+
+ // Request for member of associated event, but there is no associated event.
+ if (!the_event)
+ return false;
+
+ switch (member_) {
+ case EVENT_CATEGORY:
+ case OTHER_CATEGORY:
+ case PREV_CATEGORY:
+ *str = the_event->category;
+ return true;
+ case EVENT_NAME:
+ case OTHER_NAME:
+ case PREV_NAME:
+ *str = the_event->name;
+ return true;
+ case EVENT_ID:
+ case OTHER_ID:
+ case PREV_ID:
+ *str = the_event->id;
+ return true;
+ case EVENT_ARG:
+ case OTHER_ARG:
+ case PREV_ARG: {
+ // Search for the argument name and return its value if found.
+ auto str_i = the_event->arg_strings.find(string_);
+ if (str_i == the_event->arg_strings.end())
+ return false;
+ *str = str_i->second;
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+Query::Query(const std::string& str)
+ : type_(QUERY_STRING),
+ operator_(OP_INVALID),
+ member_(EVENT_INVALID),
+ number_(0),
+ string_(str),
+ is_pattern_(false) {
+}
+
+Query::Query(double num)
+ : type_(QUERY_NUMBER),
+ operator_(OP_INVALID),
+ member_(EVENT_INVALID),
+ number_(num),
+ is_pattern_(false) {
+}
+const Query& Query::left() const {
+ return left_->query();
+}
+
+const Query& Query::right() const {
+ return right_->query();
+}
+
+Query Query::operator==(const Query& rhs) const {
+ return Query(*this, rhs, OP_EQ);
+}
+
+Query Query::operator!=(const Query& rhs) const {
+ return Query(*this, rhs, OP_NE);
+}
+
+Query Query::operator<(const Query& rhs) const {
+ return Query(*this, rhs, OP_LT);
+}
+
+Query Query::operator<=(const Query& rhs) const {
+ return Query(*this, rhs, OP_LE);
+}
+
+Query Query::operator>(const Query& rhs) const {
+ return Query(*this, rhs, OP_GT);
+}
+
+Query Query::operator>=(const Query& rhs) const {
+ return Query(*this, rhs, OP_GE);
+}
+
+Query Query::operator&&(const Query& rhs) const {
+ return Query(*this, rhs, OP_AND);
+}
+
+Query Query::operator||(const Query& rhs) const {
+ return Query(*this, rhs, OP_OR);
+}
+
+Query Query::operator!() const {
+ return Query(*this, OP_NOT);
+}
+
+Query Query::operator+(const Query& rhs) const {
+ return Query(*this, rhs, OP_ADD);
+}
+
+Query Query::operator-(const Query& rhs) const {
+ return Query(*this, rhs, OP_SUB);
+}
+
+Query Query::operator*(const Query& rhs) const {
+ return Query(*this, rhs, OP_MUL);
+}
+
+Query Query::operator/(const Query& rhs) const {
+ return Query(*this, rhs, OP_DIV);
+}
+
+Query Query::operator%(const Query& rhs) const {
+ return Query(*this, rhs, OP_MOD);
+}
+
+Query Query::operator-() const {
+ return Query(*this, OP_NEGATE);
+}
+
+
+Query::Query(const Query& left, const Query& right, Operator binary_op)
+ : operator_(binary_op),
+ left_(new QueryNode(left)),
+ right_(new QueryNode(right)),
+ member_(EVENT_INVALID),
+ number_(0) {
+ type_ = (binary_op < OP_ADD ?
+ QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
+}
+
+Query::Query(const Query& left, Operator unary_op)
+ : operator_(unary_op),
+ left_(new QueryNode(left)),
+ member_(EVENT_INVALID),
+ number_(0) {
+ type_ = (unary_op < OP_ADD ?
+ QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
+}
+
+namespace {
+
+// Search |events| for |query| and add matches to |output|.
+size_t FindMatchingEvents(const std::vector<TraceEvent>& events,
+ const Query& query,
+ TraceEventVector* output,
+ bool ignore_metadata_events) {
+ for (const auto& i : events) {
+ if (ignore_metadata_events && i.phase == TRACE_EVENT_PHASE_METADATA)
+ continue;
+ if (query.Evaluate(i))
+ output->push_back(&i);
+ }
+ return output->size();
+}
+
+bool ParseEventsFromJson(const std::string& json,
+ std::vector<TraceEvent>* output) {
+ base::Optional<base::Value> root = base::JSONReader::Read(json);
+
+ if (!root)
+ return false;
+
+ base::Value::ListView list;
+ if (root->is_list()) {
+ list = root->GetList();
+ } else if (root->is_dict()) {
+ base::Value* trace_events = root->FindListKey("traceEvents");
+ if (!trace_events)
+ return false;
+
+ list = trace_events->GetList();
+ } else {
+ return false;
+ }
+
+ for (const auto& item : list) {
+ TraceEvent event;
+ if (!event.SetFromJSON(&item))
+ return false;
+ output->push_back(std::move(event));
+ }
+
+ return true;
+}
+
+} // namespace
+
+// TraceAnalyzer
+
+TraceAnalyzer::TraceAnalyzer()
+ : ignore_metadata_events_(false), allow_association_changes_(true) {}
+
+TraceAnalyzer::~TraceAnalyzer() = default;
+
+// static
+TraceAnalyzer* TraceAnalyzer::Create(const std::string& json_events) {
+ std::unique_ptr<TraceAnalyzer> analyzer(new TraceAnalyzer());
+ if (analyzer->SetEvents(json_events))
+ return analyzer.release();
+ return nullptr;
+}
+
+bool TraceAnalyzer::SetEvents(const std::string& json_events) {
+ raw_events_.clear();
+ if (!ParseEventsFromJson(json_events, &raw_events_))
+ return false;
+ std::stable_sort(raw_events_.begin(), raw_events_.end());
+ ParseMetadata();
+ return true;
+}
+
+void TraceAnalyzer::AssociateBeginEndEvents() {
+ using trace_analyzer::Query;
+
+ Query begin(Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN));
+ Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_END));
+ Query match(Query::EventName() == Query::OtherName() &&
+ Query::EventCategory() == Query::OtherCategory() &&
+ Query::EventTid() == Query::OtherTid() &&
+ Query::EventPid() == Query::OtherPid());
+
+ AssociateEvents(begin, end, match);
+}
+
+void TraceAnalyzer::AssociateAsyncBeginEndEvents(bool match_pid) {
+ using trace_analyzer::Query;
+
+ Query begin(
+ Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN) ||
+ Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
+ Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
+ Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_END) ||
+ Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
+ Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
+ Query match(Query::EventCategory() == Query::OtherCategory() &&
+ Query::EventId() == Query::OtherId());
+
+ if (match_pid) {
+ match = match && Query::EventPid() == Query::OtherPid();
+ }
+
+ AssociateEvents(begin, end, match);
+}
+
+void TraceAnalyzer::AssociateEvents(const Query& first,
+ const Query& second,
+ const Query& match) {
+ DCHECK(allow_association_changes_)
+ << "AssociateEvents not allowed after FindEvents";
+
+ // Search for matching begin/end event pairs. When a matching end is found,
+ // it is associated with the begin event.
+ std::vector<TraceEvent*> begin_stack;
+ for (auto& this_event : raw_events_) {
+ if (second.Evaluate(this_event)) {
+ // Search stack for matching begin, starting from end.
+ for (int stack_index = static_cast<int>(begin_stack.size()) - 1;
+ stack_index >= 0; --stack_index) {
+ TraceEvent& begin_event = *begin_stack[stack_index];
+
+ // Temporarily set other to test against the match query.
+ const TraceEvent* other_backup = begin_event.other_event;
+ begin_event.other_event = &this_event;
+ if (match.Evaluate(begin_event)) {
+ // Found a matching begin/end pair.
+ // Set the associated previous event
+ this_event.prev_event = &begin_event;
+ // Erase the matching begin event index from the stack.
+ begin_stack.erase(begin_stack.begin() + stack_index);
+ break;
+ }
+
+ // Not a match, restore original other and continue.
+ begin_event.other_event = other_backup;
+ }
+ }
+ // Even if this_event is a |second| event that has matched an earlier
+ // |first| event, it can still also be a |first| event and be associated
+ // with a later |second| event.
+ if (first.Evaluate(this_event)) {
+ begin_stack.push_back(&this_event);
+ }
+ }
+}
+
+void TraceAnalyzer::MergeAssociatedEventArgs() {
+ for (auto& i : raw_events_) {
+ // Merge all associated events with the first event.
+ const TraceEvent* other = i.other_event;
+ // Avoid looping by keeping set of encountered TraceEvents.
+ std::set<const TraceEvent*> encounters;
+ encounters.insert(&i);
+ while (other && encounters.find(other) == encounters.end()) {
+ encounters.insert(other);
+ i.arg_numbers.insert(other->arg_numbers.begin(),
+ other->arg_numbers.end());
+ i.arg_strings.insert(other->arg_strings.begin(),
+ other->arg_strings.end());
+ other = other->other_event;
+ }
+ }
+}
+
+size_t TraceAnalyzer::FindEvents(const Query& query, TraceEventVector* output) {
+ allow_association_changes_ = false;
+ output->clear();
+ return FindMatchingEvents(
+ raw_events_, query, output, ignore_metadata_events_);
+}
+
+const TraceEvent* TraceAnalyzer::FindFirstOf(const Query& query) {
+ TraceEventVector output;
+ if (FindEvents(query, &output) > 0)
+ return output.front();
+ return nullptr;
+}
+
+const TraceEvent* TraceAnalyzer::FindLastOf(const Query& query) {
+ TraceEventVector output;
+ if (FindEvents(query, &output) > 0)
+ return output.back();
+ return nullptr;
+}
+
+const std::string& TraceAnalyzer::GetThreadName(
+ const TraceEvent::ProcessThreadID& thread) {
+ // If thread is not found, just add and return empty string.
+ return thread_names_[thread];
+}
+
+void TraceAnalyzer::ParseMetadata() {
+ for (const auto& this_event : raw_events_) {
+ // Check for thread name metadata.
+ if (this_event.phase != TRACE_EVENT_PHASE_METADATA ||
+ this_event.name != "thread_name")
+ continue;
+ std::map<std::string, std::string>::const_iterator string_it =
+ this_event.arg_strings.find("name");
+ if (string_it != this_event.arg_strings.end())
+ thread_names_[this_event.thread] = string_it->second;
+ }
+}
+
+// Utility functions for collecting process-local traces and creating a
+// |TraceAnalyzer| from the result.
+
+void Start(const std::string& category_filter_string) {
+ DCHECK(!base::trace_event::TraceLog::GetInstance()->IsEnabled());
+ base::trace_event::TraceLog::GetInstance()->SetEnabled(
+ base::trace_event::TraceConfig(category_filter_string, ""),
+ base::trace_event::TraceLog::RECORDING_MODE);
+}
+
+std::unique_ptr<TraceAnalyzer> Stop() {
+ DCHECK(base::trace_event::TraceLog::GetInstance()->IsEnabled());
+ base::trace_event::TraceLog::GetInstance()->SetDisabled();
+
+ base::trace_event::TraceResultBuffer buffer;
+ base::trace_event::TraceResultBuffer::SimpleOutput trace_output;
+ buffer.SetOutputCallback(trace_output.GetCallback());
+ base::RunLoop run_loop;
+ buffer.Start();
+ base::trace_event::TraceLog::GetInstance()->Flush(
+ base::BindRepeating(&OnTraceDataCollected, run_loop.QuitClosure(),
+ base::Unretained(&buffer)));
+ run_loop.Run();
+ buffer.Finish();
+
+ return base::WrapUnique(TraceAnalyzer::Create(trace_output.json_output));
+}
+
+// TraceEventVector utility functions.
+
+bool GetRateStats(const TraceEventVector& events,
+ RateStats* stats,
+ const RateStatsOptions* options) {
+ DCHECK(stats);
+ // Need at least 3 events to calculate rate stats.
+ const size_t kMinEvents = 3;
+ if (events.size() < kMinEvents) {
+ LOG(ERROR) << "Not enough events: " << events.size();
+ return false;
+ }
+
+ std::vector<double> deltas;
+ size_t num_deltas = events.size() - 1;
+ for (size_t i = 0; i < num_deltas; ++i) {
+ double delta = events.at(i + 1)->timestamp - events.at(i)->timestamp;
+ if (delta < 0.0) {
+ LOG(ERROR) << "Events are out of order";
+ return false;
+ }
+ deltas.push_back(delta);
+ }
+
+ std::sort(deltas.begin(), deltas.end());
+
+ if (options) {
+ if (options->trim_min + options->trim_max > events.size() - kMinEvents) {
+ LOG(ERROR) << "Attempt to trim too many events";
+ return false;
+ }
+ deltas.erase(deltas.begin(), deltas.begin() + options->trim_min);
+ deltas.erase(deltas.end() - options->trim_max, deltas.end());
+ }
+
+ num_deltas = deltas.size();
+ double delta_sum = 0.0;
+ for (size_t i = 0; i < num_deltas; ++i)
+ delta_sum += deltas[i];
+
+ stats->min_us = *std::min_element(deltas.begin(), deltas.end());
+ stats->max_us = *std::max_element(deltas.begin(), deltas.end());
+ stats->mean_us = delta_sum / static_cast<double>(num_deltas);
+
+ double sum_mean_offsets_squared = 0.0;
+ for (size_t i = 0; i < num_deltas; ++i) {
+ double offset = fabs(deltas[i] - stats->mean_us);
+ sum_mean_offsets_squared += offset * offset;
+ }
+ stats->standard_deviation_us =
+ sqrt(sum_mean_offsets_squared / static_cast<double>(num_deltas - 1));
+
+ return true;
+}
+
+bool FindFirstOf(const TraceEventVector& events,
+ const Query& query,
+ size_t position,
+ size_t* return_index) {
+ DCHECK(return_index);
+ for (size_t i = position; i < events.size(); ++i) {
+ if (query.Evaluate(*events[i])) {
+ *return_index = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool FindLastOf(const TraceEventVector& events,
+ const Query& query,
+ size_t position,
+ size_t* return_index) {
+ DCHECK(return_index);
+ for (size_t i = std::min(position + 1, events.size()); i != 0; --i) {
+ if (query.Evaluate(*events[i - 1])) {
+ *return_index = i - 1;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool FindClosest(const TraceEventVector& events,
+ const Query& query,
+ size_t position,
+ size_t* return_closest,
+ size_t* return_second_closest) {
+ DCHECK(return_closest);
+ if (events.empty() || position >= events.size())
+ return false;
+ size_t closest = events.size();
+ size_t second_closest = events.size();
+ for (size_t i = 0; i < events.size(); ++i) {
+ if (!query.Evaluate(*events.at(i)))
+ continue;
+ if (closest == events.size()) {
+ closest = i;
+ continue;
+ }
+ if (fabs(events.at(i)->timestamp - events.at(position)->timestamp) <
+ fabs(events.at(closest)->timestamp - events.at(position)->timestamp)) {
+ second_closest = closest;
+ closest = i;
+ } else if (second_closest == events.size()) {
+ second_closest = i;
+ }
+ }
+
+ if (closest < events.size() &&
+ (!return_second_closest || second_closest < events.size())) {
+ *return_closest = closest;
+ if (return_second_closest)
+ *return_second_closest = second_closest;
+ return true;
+ }
+
+ return false;
+}
+
+size_t CountMatches(const TraceEventVector& events,
+ const Query& query,
+ size_t begin_position,
+ size_t end_position) {
+ if (begin_position >= events.size())
+ return 0u;
+ end_position = (end_position < events.size()) ? end_position : events.size();
+ size_t count = 0u;
+ for (size_t i = begin_position; i < end_position; ++i) {
+ if (query.Evaluate(*events.at(i)))
+ ++count;
+ }
+ return count;
+}
+
+} // namespace trace_analyzer
diff --git a/chromium/base/test/trace_event_analyzer.h b/chromium/base/test/trace_event_analyzer.h
new file mode 100644
index 00000000000..dcdd2e4b5ec
--- /dev/null
+++ b/chromium/base/test/trace_event_analyzer.h
@@ -0,0 +1,842 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Use trace_analyzer::Query and trace_analyzer::TraceAnalyzer to search for
+// specific trace events that were generated by the trace_event.h API.
+//
+// Basic procedure:
+// - Get trace events JSON string from base::trace_event::TraceLog.
+// - Create TraceAnalyzer with JSON string.
+// - Call TraceAnalyzer::AssociateBeginEndEvents (optional).
+// - Call TraceAnalyzer::AssociateEvents (zero or more times).
+// - Call TraceAnalyzer::FindEvents with queries to find specific events.
+//
+// A Query is a boolean expression tree that evaluates to true or false for a
+// given trace event. Queries can be combined into a tree using boolean,
+// arithmetic and comparison operators that refer to data of an individual trace
+// event.
+//
+// The events are returned as trace_analyzer::TraceEvent objects.
+// TraceEvent contains a single trace event's data, as well as a pointer to
+// a related trace event. The related trace event is typically the matching end
+// of a begin event or the matching begin of an end event.
+//
+// The following examples use this basic setup code to construct TraceAnalyzer
+// with the json trace string retrieved from TraceLog and construct an event
+// vector for retrieving events:
+//
+// TraceAnalyzer analyzer(json_events);
+// TraceEventVector events;
+//
+// EXAMPLE 1: Find events named "my_event".
+//
+// analyzer.FindEvents(Query(EVENT_NAME) == "my_event", &events);
+//
+// EXAMPLE 2: Find begin events named "my_event" with duration > 1 second.
+//
+// Query q = (Query(EVENT_NAME) == Query::String("my_event") &&
+// Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN) &&
+// Query(EVENT_DURATION) > Query::Double(1000000.0));
+// analyzer.FindEvents(q, &events);
+//
+// EXAMPLE 3: Associating event pairs across threads.
+//
+// If the test needs to analyze something that starts and ends on different
+// threads, the test needs to use INSTANT events. The typical procedure is to
+// specify the same unique ID as a TRACE_EVENT argument on both the start and
+// finish INSTANT events. Then use the following procedure to associate those
+// events.
+//
+// Step 1: instrument code with custom begin/end trace events.
+// [Thread 1 tracing code]
+// TRACE_EVENT_INSTANT1("test_latency", "timing1_begin", "id", 3);
+// [Thread 2 tracing code]
+// TRACE_EVENT_INSTANT1("test_latency", "timing1_end", "id", 3);
+//
+// Step 2: associate these custom begin/end pairs.
+// Query begin(Query(EVENT_NAME) == Query::String("timing1_begin"));
+// Query end(Query(EVENT_NAME) == Query::String("timing1_end"));
+// Query match(Query(EVENT_ARG, "id") == Query(OTHER_ARG, "id"));
+// analyzer.AssociateEvents(begin, end, match);
+//
+// Step 3: search for "timing1_begin" events with existing other event.
+// Query q = (Query(EVENT_NAME) == Query::String("timing1_begin") &&
+// Query(EVENT_HAS_OTHER));
+// analyzer.FindEvents(q, &events);
+//
+// Step 4: analyze events, such as checking durations.
+// for (size_t i = 0; i < events.size(); ++i) {
+// double duration;
+// EXPECT_TRUE(events[i].GetAbsTimeToOtherEvent(&duration));
+// EXPECT_LT(duration, 1000000.0/60.0); // expect less than 1/60 second.
+// }
+//
+// There are two helper functions, Start(category_filter_string) and Stop(), for
+// facilitating the collection of process-local traces and building a
+// TraceAnalyzer from them. A typical test, that uses the helper functions,
+// looks like the following:
+//
+// TEST_F(...) {
+// Start("*");
+// [Invoke the functions you want to test their traces]
+// auto analyzer = Stop();
+//
+// [Use the analyzer to verify produced traces, as explained above]
+// }
+//
+// Note: The Stop() function needs a SingleThreadTaskRunner.
+
+#ifndef BASE_TEST_TRACE_EVENT_ANALYZER_H_
+#define BASE_TEST_TRACE_EVENT_ANALYZER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+class Value;
+}
+
+namespace trace_analyzer {
+class QueryNode;
+
+// trace_analyzer::TraceEvent is a more convenient form of the
+// base::trace_event::TraceEvent class to make tracing-based tests easier to
+// write.
+struct TraceEvent {
+ // ProcessThreadID contains a Process ID and Thread ID.
+ struct ProcessThreadID {
+ ProcessThreadID() : process_id(0), thread_id(0) {}
+ ProcessThreadID(int process_id, int thread_id)
+ : process_id(process_id), thread_id(thread_id) {}
+ bool operator< (const ProcessThreadID& rhs) const {
+ if (process_id != rhs.process_id)
+ return process_id < rhs.process_id;
+ return thread_id < rhs.thread_id;
+ }
+ int process_id;
+ int thread_id;
+ };
+
+ TraceEvent();
+ TraceEvent(TraceEvent&& other);
+ ~TraceEvent();
+
+ bool SetFromJSON(const base::Value* event_value) WARN_UNUSED_RESULT;
+
+ bool operator< (const TraceEvent& rhs) const {
+ return timestamp < rhs.timestamp;
+ }
+
+ TraceEvent& operator=(TraceEvent&& rhs);
+
+ bool has_other_event() const { return other_event; }
+
+ // Returns absolute duration in microseconds between this event and other
+ // event. Must have already verified that other_event exists by
+ // Query(EVENT_HAS_OTHER) or by calling has_other_event().
+ double GetAbsTimeToOtherEvent() const;
+
+ // Return the argument value if it exists and it is a string.
+ bool GetArgAsString(const std::string& name, std::string* arg) const;
+ // Return the argument value if it exists and it is a number.
+ bool GetArgAsNumber(const std::string& name, double* arg) const;
+ // Return the argument value if it exists.
+ bool GetArgAsValue(const std::string& name,
+ std::unique_ptr<base::Value>* arg) const;
+
+ // Check if argument exists and is string.
+ bool HasStringArg(const std::string& name) const;
+ // Check if argument exists and is number (double, int or bool).
+ bool HasNumberArg(const std::string& name) const;
+ // Check if argument exists.
+ bool HasArg(const std::string& name) const;
+
+ // Get known existing arguments as specific types.
+ // Useful when you have already queried the argument with
+ // Query(HAS_NUMBER_ARG) or Query(HAS_STRING_ARG).
+ std::string GetKnownArgAsString(const std::string& name) const;
+ double GetKnownArgAsDouble(const std::string& name) const;
+ int GetKnownArgAsInt(const std::string& name) const;
+ bool GetKnownArgAsBool(const std::string& name) const;
+ std::unique_ptr<base::Value> GetKnownArgAsValue(
+ const std::string& name) const;
+
+ // Process ID and Thread ID.
+ ProcessThreadID thread;
+
+ // Time since epoch in microseconds.
+ // Stored as double to match its JSON representation.
+ double timestamp;
+ double duration;
+ char phase;
+ std::string category;
+ std::string name;
+ std::string id;
+ double thread_duration = 0.0;
+ double thread_timestamp = 0.0;
+ std::string scope;
+ std::string bind_id;
+ bool flow_out = false;
+ bool flow_in = false;
+ std::string global_id2;
+ std::string local_id2;
+
+ // All numbers and bool values from TraceEvent args are cast to double.
+ // bool becomes 1.0 (true) or 0.0 (false).
+ std::map<std::string, double> arg_numbers;
+ std::map<std::string, std::string> arg_strings;
+ std::map<std::string, std::unique_ptr<base::Value>> arg_values;
+
+ // The other event associated with this event (or NULL).
+ const TraceEvent* other_event;
+
+ // A back-link for |other_event|. That is, if other_event is not null, then
+ // |event->other_event->prev_event == event| is always true.
+ const TraceEvent* prev_event;
+};
+
+typedef std::vector<const TraceEvent*> TraceEventVector;
+
+class Query {
+ public:
+ Query(const Query& query);
+
+ ~Query();
+
+ ////////////////////////////////////////////////////////////////
+ // Query literal values
+
+ // Compare with the given string.
+ static Query String(const std::string& str);
+
+ // Compare with the given number.
+ static Query Double(double num);
+ static Query Int(int32_t num);
+ static Query Uint(uint32_t num);
+
+ // Compare with the given bool.
+ static Query Bool(bool boolean);
+
+ // Compare with the given phase.
+ static Query Phase(char phase);
+
+ // Compare with the given string pattern. Only works with == and != operators.
+ // Example: Query(EVENT_NAME) == Query::Pattern("MyEvent*")
+ static Query Pattern(const std::string& pattern);
+
+ ////////////////////////////////////////////////////////////////
+ // Query event members
+
+ static Query EventPid() { return Query(EVENT_PID); }
+
+ static Query EventTid() { return Query(EVENT_TID); }
+
+ // Return the timestamp of the event in microseconds since epoch.
+ static Query EventTime() { return Query(EVENT_TIME); }
+
+ // Return the absolute time between event and other event in microseconds.
+ // Only works if Query::EventHasOther() == true.
+ static Query EventDuration() { return Query(EVENT_DURATION); }
+
+ // Return the duration of a COMPLETE event.
+ static Query EventCompleteDuration() {
+ return Query(EVENT_COMPLETE_DURATION);
+ }
+
+ static Query EventPhase() { return Query(EVENT_PHASE); }
+
+ static Query EventCategory() { return Query(EVENT_CATEGORY); }
+
+ static Query EventName() { return Query(EVENT_NAME); }
+
+ static Query EventId() { return Query(EVENT_ID); }
+
+ static Query EventPidIs(int process_id) {
+ return Query(EVENT_PID) == Query::Int(process_id);
+ }
+
+ static Query EventTidIs(int thread_id) {
+ return Query(EVENT_TID) == Query::Int(thread_id);
+ }
+
+ static Query EventThreadIs(const TraceEvent::ProcessThreadID& thread) {
+ return EventPidIs(thread.process_id) && EventTidIs(thread.thread_id);
+ }
+
+ static Query EventTimeIs(double timestamp) {
+ return Query(EVENT_TIME) == Query::Double(timestamp);
+ }
+
+ static Query EventDurationIs(double duration) {
+ return Query(EVENT_DURATION) == Query::Double(duration);
+ }
+
+ static Query EventPhaseIs(char phase) {
+ return Query(EVENT_PHASE) == Query::Phase(phase);
+ }
+
+ static Query EventCategoryIs(const std::string& category) {
+ return Query(EVENT_CATEGORY) == Query::String(category);
+ }
+
+ static Query EventNameIs(const std::string& name) {
+ return Query(EVENT_NAME) == Query::String(name);
+ }
+
+ static Query EventIdIs(const std::string& id) {
+ return Query(EVENT_ID) == Query::String(id);
+ }
+
+ // Evaluates to true if arg exists and is a string.
+ static Query EventHasStringArg(const std::string& arg_name) {
+ return Query(EVENT_HAS_STRING_ARG, arg_name);
+ }
+
+ // Evaluates to true if arg exists and is a number.
+ // Number arguments include types double, int and bool.
+ static Query EventHasNumberArg(const std::string& arg_name) {
+ return Query(EVENT_HAS_NUMBER_ARG, arg_name);
+ }
+
+ // Evaluates to arg value (string or number).
+ static Query EventArg(const std::string& arg_name) {
+ return Query(EVENT_ARG, arg_name);
+ }
+
+ // Return true if associated event exists.
+ static Query EventHasOther() { return Query(EVENT_HAS_OTHER); }
+
+ // Access the associated other_event's members:
+
+ static Query OtherPid() { return Query(OTHER_PID); }
+
+ static Query OtherTid() { return Query(OTHER_TID); }
+
+ static Query OtherTime() { return Query(OTHER_TIME); }
+
+ static Query OtherPhase() { return Query(OTHER_PHASE); }
+
+ static Query OtherCategory() { return Query(OTHER_CATEGORY); }
+
+ static Query OtherName() { return Query(OTHER_NAME); }
+
+ static Query OtherId() { return Query(OTHER_ID); }
+
+ static Query OtherPidIs(int process_id) {
+ return Query(OTHER_PID) == Query::Int(process_id);
+ }
+
+ static Query OtherTidIs(int thread_id) {
+ return Query(OTHER_TID) == Query::Int(thread_id);
+ }
+
+ static Query OtherThreadIs(const TraceEvent::ProcessThreadID& thread) {
+ return OtherPidIs(thread.process_id) && OtherTidIs(thread.thread_id);
+ }
+
+ static Query OtherTimeIs(double timestamp) {
+ return Query(OTHER_TIME) == Query::Double(timestamp);
+ }
+
+ static Query OtherPhaseIs(char phase) {
+ return Query(OTHER_PHASE) == Query::Phase(phase);
+ }
+
+ static Query OtherCategoryIs(const std::string& category) {
+ return Query(OTHER_CATEGORY) == Query::String(category);
+ }
+
+ static Query OtherNameIs(const std::string& name) {
+ return Query(OTHER_NAME) == Query::String(name);
+ }
+
+ static Query OtherIdIs(const std::string& id) {
+ return Query(OTHER_ID) == Query::String(id);
+ }
+
+ // Evaluates to true if arg exists and is a string.
+ static Query OtherHasStringArg(const std::string& arg_name) {
+ return Query(OTHER_HAS_STRING_ARG, arg_name);
+ }
+
+ // Evaluates to true if arg exists and is a number.
+ // Number arguments include types double, int and bool.
+ static Query OtherHasNumberArg(const std::string& arg_name) {
+ return Query(OTHER_HAS_NUMBER_ARG, arg_name);
+ }
+
+ // Evaluates to arg value (string or number).
+ static Query OtherArg(const std::string& arg_name) {
+ return Query(OTHER_ARG, arg_name);
+ }
+
+ // Access the associated prev_event's members:
+
+ static Query PrevPid() { return Query(PREV_PID); }
+
+ static Query PrevTid() { return Query(PREV_TID); }
+
+ static Query PrevTime() { return Query(PREV_TIME); }
+
+ static Query PrevPhase() { return Query(PREV_PHASE); }
+
+ static Query PrevCategory() { return Query(PREV_CATEGORY); }
+
+ static Query PrevName() { return Query(PREV_NAME); }
+
+ static Query PrevId() { return Query(PREV_ID); }
+
+ static Query PrevPidIs(int process_id) {
+ return Query(PREV_PID) == Query::Int(process_id);
+ }
+
+ static Query PrevTidIs(int thread_id) {
+ return Query(PREV_TID) == Query::Int(thread_id);
+ }
+
+ static Query PrevThreadIs(const TraceEvent::ProcessThreadID& thread) {
+ return PrevPidIs(thread.process_id) && PrevTidIs(thread.thread_id);
+ }
+
+ static Query PrevTimeIs(double timestamp) {
+ return Query(PREV_TIME) == Query::Double(timestamp);
+ }
+
+ static Query PrevPhaseIs(char phase) {
+ return Query(PREV_PHASE) == Query::Phase(phase);
+ }
+
+ static Query PrevCategoryIs(const std::string& category) {
+ return Query(PREV_CATEGORY) == Query::String(category);
+ }
+
+ static Query PrevNameIs(const std::string& name) {
+ return Query(PREV_NAME) == Query::String(name);
+ }
+
+ static Query PrevIdIs(const std::string& id) {
+ return Query(PREV_ID) == Query::String(id);
+ }
+
+ // Evaluates to true if arg exists and is a string.
+ static Query PrevHasStringArg(const std::string& arg_name) {
+ return Query(PREV_HAS_STRING_ARG, arg_name);
+ }
+
+ // Evaluates to true if arg exists and is a number.
+ // Number arguments include types double, int and bool.
+ static Query PrevHasNumberArg(const std::string& arg_name) {
+ return Query(PREV_HAS_NUMBER_ARG, arg_name);
+ }
+
+ // Evaluates to arg value (string or number).
+ static Query PrevArg(const std::string& arg_name) {
+ return Query(PREV_ARG, arg_name);
+ }
+
+ ////////////////////////////////////////////////////////////////
+ // Common queries:
+
+ // Find BEGIN events that have a corresponding END event.
+ static Query MatchBeginWithEnd() {
+ return (Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN)) &&
+ Query(EVENT_HAS_OTHER);
+ }
+
+ // Find COMPLETE events.
+ static Query MatchComplete() {
+ return (Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_COMPLETE));
+ }
+
+ // Find ASYNC_BEGIN events that have a corresponding ASYNC_END event.
+ static Query MatchAsyncBeginWithNext() {
+ return (Query(EVENT_PHASE) ==
+ Query::Phase(TRACE_EVENT_PHASE_ASYNC_BEGIN)) &&
+ Query(EVENT_HAS_OTHER);
+ }
+
+ // Find BEGIN events of given |name| which also have associated END events.
+ static Query MatchBeginName(const std::string& name) {
+ return (Query(EVENT_NAME) == Query(name)) && MatchBeginWithEnd();
+ }
+
+ // Find COMPLETE events of given |name|.
+ static Query MatchCompleteName(const std::string& name) {
+ return (Query(EVENT_NAME) == Query(name)) && MatchComplete();
+ }
+
+ // Match given Process ID and Thread ID.
+ static Query MatchThread(const TraceEvent::ProcessThreadID& thread) {
+ return (Query(EVENT_PID) == Query::Int(thread.process_id)) &&
+ (Query(EVENT_TID) == Query::Int(thread.thread_id));
+ }
+
+ // Match event pair that spans multiple threads.
+ static Query MatchCrossThread() {
+ return (Query(EVENT_PID) != Query(OTHER_PID)) ||
+ (Query(EVENT_TID) != Query(OTHER_TID));
+ }
+
+ ////////////////////////////////////////////////////////////////
+ // Operators:
+
+ // Boolean operators:
+ Query operator==(const Query& rhs) const;
+ Query operator!=(const Query& rhs) const;
+ Query operator< (const Query& rhs) const;
+ Query operator<=(const Query& rhs) const;
+ Query operator> (const Query& rhs) const;
+ Query operator>=(const Query& rhs) const;
+ Query operator&&(const Query& rhs) const;
+ Query operator||(const Query& rhs) const;
+ Query operator!() const;
+
+ // Arithmetic operators:
+ // Following operators are applied to double arguments:
+ Query operator+(const Query& rhs) const;
+ Query operator-(const Query& rhs) const;
+ Query operator*(const Query& rhs) const;
+ Query operator/(const Query& rhs) const;
+ Query operator-() const;
+ // Mod operates on int64_t args (doubles are casted to int64_t beforehand):
+ Query operator%(const Query& rhs) const;
+
+ // Return true if the given event matches this query tree.
+ // This is a recursive method that walks the query tree.
+ bool Evaluate(const TraceEvent& event) const;
+
+ enum TraceEventMember {
+ EVENT_INVALID,
+ EVENT_PID,
+ EVENT_TID,
+ EVENT_TIME,
+ EVENT_DURATION,
+ EVENT_COMPLETE_DURATION,
+ EVENT_PHASE,
+ EVENT_CATEGORY,
+ EVENT_NAME,
+ EVENT_ID,
+ EVENT_HAS_STRING_ARG,
+ EVENT_HAS_NUMBER_ARG,
+ EVENT_ARG,
+ EVENT_HAS_OTHER,
+ EVENT_HAS_PREV,
+
+ OTHER_PID,
+ OTHER_TID,
+ OTHER_TIME,
+ OTHER_PHASE,
+ OTHER_CATEGORY,
+ OTHER_NAME,
+ OTHER_ID,
+ OTHER_HAS_STRING_ARG,
+ OTHER_HAS_NUMBER_ARG,
+ OTHER_ARG,
+
+ PREV_PID,
+ PREV_TID,
+ PREV_TIME,
+ PREV_PHASE,
+ PREV_CATEGORY,
+ PREV_NAME,
+ PREV_ID,
+ PREV_HAS_STRING_ARG,
+ PREV_HAS_NUMBER_ARG,
+ PREV_ARG,
+
+ OTHER_FIRST_MEMBER = OTHER_PID,
+ OTHER_LAST_MEMBER = OTHER_ARG,
+
+ PREV_FIRST_MEMBER = PREV_PID,
+ PREV_LAST_MEMBER = PREV_ARG,
+ };
+
+ enum Operator {
+ OP_INVALID,
+ // Boolean operators:
+ OP_EQ,
+ OP_NE,
+ OP_LT,
+ OP_LE,
+ OP_GT,
+ OP_GE,
+ OP_AND,
+ OP_OR,
+ OP_NOT,
+ // Arithmetic operators:
+ OP_ADD,
+ OP_SUB,
+ OP_MUL,
+ OP_DIV,
+ OP_MOD,
+ OP_NEGATE
+ };
+
+ enum QueryType {
+ QUERY_BOOLEAN_OPERATOR,
+ QUERY_ARITHMETIC_OPERATOR,
+ QUERY_EVENT_MEMBER,
+ QUERY_NUMBER,
+ QUERY_STRING
+ };
+
+ // Compare with the given member.
+ explicit Query(TraceEventMember member);
+
+ // Compare with the given member argument value.
+ Query(TraceEventMember member, const std::string& arg_name);
+
+ // Compare with the given string.
+ explicit Query(const std::string& str);
+
+ // Compare with the given number.
+ explicit Query(double num);
+
+ // Construct a boolean Query that returns (left <binary_op> right).
+ Query(const Query& left, const Query& right, Operator binary_op);
+
+ // Construct a boolean Query that returns (<binary_op> left).
+ Query(const Query& left, Operator unary_op);
+
+ // Try to compare left_ against right_ based on operator_.
+ // If either left or right does not convert to double, false is returned.
+ // Otherwise, true is returned and |result| is set to the comparison result.
+ bool CompareAsDouble(const TraceEvent& event, bool* result) const;
+
+ // Try to compare left_ against right_ based on operator_.
+ // If either left or right does not convert to string, false is returned.
+ // Otherwise, true is returned and |result| is set to the comparison result.
+ bool CompareAsString(const TraceEvent& event, bool* result) const;
+
+ // Attempt to convert this Query to a double. On success, true is returned
+ // and the double value is stored in |num|.
+ bool GetAsDouble(const TraceEvent& event, double* num) const;
+
+ // Attempt to convert this Query to a string. On success, true is returned
+ // and the string value is stored in |str|.
+ bool GetAsString(const TraceEvent& event, std::string* str) const;
+
+ // Evaluate this Query as an arithmetic operator on left_ and right_.
+ bool EvaluateArithmeticOperator(const TraceEvent& event,
+ double* num) const;
+
+ // For QUERY_EVENT_MEMBER Query: attempt to get the double value of the Query.
+ bool GetMemberValueAsDouble(const TraceEvent& event, double* num) const;
+
+ // For QUERY_EVENT_MEMBER Query: attempt to get the string value of the Query.
+ bool GetMemberValueAsString(const TraceEvent& event, std::string* num) const;
+
+ // Does this Query represent a value?
+ bool is_value() const { return type_ != QUERY_BOOLEAN_OPERATOR; }
+
+ bool is_unary_operator() const {
+ return operator_ == OP_NOT || operator_ == OP_NEGATE;
+ }
+
+ bool is_comparison_operator() const {
+ return operator_ != OP_INVALID && operator_ < OP_AND;
+ }
+
+ static const TraceEvent* SelectTargetEvent(const TraceEvent* ev,
+ TraceEventMember member);
+
+ const Query& left() const;
+ const Query& right() const;
+
+ private:
+ QueryType type_;
+ Operator operator_;
+ scoped_refptr<QueryNode> left_;
+ scoped_refptr<QueryNode> right_;
+ TraceEventMember member_;
+ double number_;
+ std::string string_;
+ bool is_pattern_;
+};
+
+// Implementation detail:
+// QueryNode allows Query to store a ref-counted query tree.
+class QueryNode : public base::RefCounted<QueryNode> {
+ public:
+ explicit QueryNode(const Query& query);
+ const Query& query() const { return query_; }
+
+ private:
+ friend class base::RefCounted<QueryNode>;
+ ~QueryNode();
+
+ Query query_;
+};
+
+// TraceAnalyzer helps tests search for trace events.
+class TraceAnalyzer {
+ public:
+ ~TraceAnalyzer();
+
+ // Use trace events from JSON string generated by tracing API.
+ // Returns non-NULL if the JSON is successfully parsed.
+ static TraceAnalyzer* Create(const std::string& json_events)
+ WARN_UNUSED_RESULT;
+
+ void SetIgnoreMetadataEvents(bool ignore) {
+ ignore_metadata_events_ = ignore;
+ }
+
+ // Associate BEGIN and END events with each other. This allows Query(OTHER_*)
+ // to access the associated event and enables Query(EVENT_DURATION).
+ // An end event will match the most recent begin event with the same name,
+ // category, process ID and thread ID. This matches what is shown in
+ // about:tracing. After association, the BEGIN event will point to the
+ // matching END event, but the END event will not point to the BEGIN event.
+ void AssociateBeginEndEvents();
+
+ // Associate ASYNC_BEGIN, ASYNC_STEP and ASYNC_END events with each other.
+ // An ASYNC_END event will match the most recent ASYNC_BEGIN or ASYNC_STEP
+ // event with the same name, category, and ID. This creates a singly linked
+ // list of ASYNC_BEGIN->ASYNC_STEP...->ASYNC_END.
+ // |match_pid| - If true, will only match async events which are running
+ // under the same process ID, otherwise will allow linking
+ // async events from different processes.
+ void AssociateAsyncBeginEndEvents(bool match_pid = true);
+
+ // AssociateEvents can be used to customize event associations by setting the
+ // other_event member of TraceEvent. This should be used to associate two
+ // INSTANT events.
+ //
+ // The assumptions are:
+ // - |first| events occur before |second| events.
+ // - the closest matching |second| event is the correct match.
+ //
+ // |first| - Eligible |first| events match this query.
+ // |second| - Eligible |second| events match this query.
+ // |match| - This query is run on the |first| event. The OTHER_* EventMember
+ // queries will point to an eligible |second| event. The query
+ // should evaluate to true if the |first|/|second| pair is a match.
+ //
+ // When a match is found, the pair will be associated by having the first
+ // event's other_event member point to the other. AssociateEvents does not
+ // clear previous associations, so it is possible to associate multiple pairs
+ // of events by calling AssociateEvents more than once with different queries.
+ //
+ // NOTE: AssociateEvents will overwrite existing other_event associations if
+ // the queries pass for events that already had a previous association.
+ //
+ // After calling any Find* method, it is not allowed to call AssociateEvents
+ // again.
+ void AssociateEvents(const Query& first,
+ const Query& second,
+ const Query& match);
+
+ // For each event, copy its arguments to the other_event argument map. If
+ // argument name already exists, it will not be overwritten.
+ void MergeAssociatedEventArgs();
+
+ // Find all events that match query and replace output vector.
+ size_t FindEvents(const Query& query, TraceEventVector* output);
+
+ // Find first event that matches query or NULL if not found.
+ const TraceEvent* FindFirstOf(const Query& query);
+
+ // Find last event that matches query or NULL if not found.
+ const TraceEvent* FindLastOf(const Query& query);
+
+ const std::string& GetThreadName(const TraceEvent::ProcessThreadID& thread);
+
+ private:
+ TraceAnalyzer();
+
+ bool SetEvents(const std::string& json_events) WARN_UNUSED_RESULT;
+
+ // Read metadata (thread names, etc) from events.
+ void ParseMetadata();
+
+ std::map<TraceEvent::ProcessThreadID, std::string> thread_names_;
+ std::vector<TraceEvent> raw_events_;
+ bool ignore_metadata_events_;
+ bool allow_association_changes_;
+
+ DISALLOW_COPY_AND_ASSIGN(TraceAnalyzer);
+};
+
+// Utility functions for collecting process-local traces and creating a
+// |TraceAnalyzer| from the result. Please see comments in trace_config.h to
+// understand how the |category_filter_string| works. Use "*" to enable all
+// default categories.
+void Start(const std::string& category_filter_string);
+std::unique_ptr<TraceAnalyzer> Stop();
+
+// Utility functions for TraceEventVector.
+
+struct RateStats {
+ double min_us;
+ double max_us;
+ double mean_us;
+ double standard_deviation_us;
+};
+
+struct RateStatsOptions {
+ RateStatsOptions() : trim_min(0u), trim_max(0u) {}
+ // After the times between events are sorted, the number of specified elements
+ // will be trimmed before calculating the RateStats. This is useful in cases
+ // where extreme outliers are tolerable and should not skew the overall
+ // average.
+ size_t trim_min; // Trim this many minimum times.
+ size_t trim_max; // Trim this many maximum times.
+};
+
+// Calculate min/max/mean and standard deviation from the times between
+// adjacent events.
+bool GetRateStats(const TraceEventVector& events,
+ RateStats* stats,
+ const RateStatsOptions* options);
+
+// Starting from |position|, find the first event that matches |query|.
+// Returns true if found, false otherwise.
+bool FindFirstOf(const TraceEventVector& events,
+ const Query& query,
+ size_t position,
+ size_t* return_index);
+
+// Starting from |position|, find the last event that matches |query|.
+// Returns true if found, false otherwise.
+bool FindLastOf(const TraceEventVector& events,
+ const Query& query,
+ size_t position,
+ size_t* return_index);
+
+// Find the closest events to |position| in time that match |query|.
+// return_second_closest may be NULL. Closeness is determined by comparing
+// with the event timestamp.
+// Returns true if found, false otherwise. If both return parameters are
+// requested, both must be found for a successful result.
+bool FindClosest(const TraceEventVector& events,
+ const Query& query,
+ size_t position,
+ size_t* return_closest,
+ size_t* return_second_closest);
+
+// Count matches, inclusive of |begin_position|, exclusive of |end_position|.
+size_t CountMatches(const TraceEventVector& events,
+ const Query& query,
+ size_t begin_position,
+ size_t end_position);
+
+// Count all matches.
+static inline size_t CountMatches(const TraceEventVector& events,
+ const Query& query) {
+ return CountMatches(events, query, 0u, events.size());
+}
+
+} // namespace trace_analyzer
+
+#endif // BASE_TEST_TRACE_EVENT_ANALYZER_H_
diff --git a/chromium/base/test/trace_event_analyzer_unittest.cc b/chromium/base/test/trace_event_analyzer_unittest.cc
new file mode 100644
index 00000000000..259fd95264b
--- /dev/null
+++ b/chromium/base/test/trace_event_analyzer_unittest.cc
@@ -0,0 +1,959 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/trace_event_analyzer.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/bind.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/trace_event/trace_buffer.h"
+#include "base/trace_event/traced_value.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace trace_analyzer {
+
+namespace {
+
+class TraceEventAnalyzerTest : public testing::Test {
+ public:
+ void ManualSetUp();
+ void OnTraceDataCollected(
+ base::WaitableEvent* flush_complete_event,
+ const scoped_refptr<base::RefCountedString>& json_events_str,
+ bool has_more_events);
+ void BeginTracing();
+ void EndTracing();
+
+ base::trace_event::TraceResultBuffer::SimpleOutput output_;
+ base::trace_event::TraceResultBuffer buffer_;
+};
+
+void TraceEventAnalyzerTest::ManualSetUp() {
+ ASSERT_TRUE(base::trace_event::TraceLog::GetInstance());
+ buffer_.SetOutputCallback(output_.GetCallback());
+ output_.json_output.clear();
+}
+
+void TraceEventAnalyzerTest::OnTraceDataCollected(
+ base::WaitableEvent* flush_complete_event,
+ const scoped_refptr<base::RefCountedString>& json_events_str,
+ bool has_more_events) {
+ buffer_.AddFragment(json_events_str->data());
+ if (!has_more_events)
+ flush_complete_event->Signal();
+}
+
+void TraceEventAnalyzerTest::BeginTracing() {
+ output_.json_output.clear();
+ buffer_.Start();
+ base::trace_event::TraceLog::GetInstance()->SetEnabled(
+ base::trace_event::TraceConfig("*", ""),
+ base::trace_event::TraceLog::RECORDING_MODE);
+}
+
+void TraceEventAnalyzerTest::EndTracing() {
+ base::trace_event::TraceLog::GetInstance()->SetDisabled();
+ base::WaitableEvent flush_complete_event(
+ base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ base::trace_event::TraceLog::GetInstance()->Flush(base::BindRepeating(
+ &TraceEventAnalyzerTest::OnTraceDataCollected, base::Unretained(this),
+ base::Unretained(&flush_complete_event)));
+ flush_complete_event.Wait();
+ buffer_.Finish();
+}
+
+} // namespace
+
+TEST_F(TraceEventAnalyzerTest, NoEvents) {
+ ManualSetUp();
+
+ // Create an empty JSON event string:
+ buffer_.Start();
+ buffer_.Finish();
+
+ std::unique_ptr<TraceAnalyzer> analyzer(
+ TraceAnalyzer::Create(output_.json_output));
+ ASSERT_TRUE(analyzer.get());
+
+ // Search for all events and verify that nothing is returned.
+ TraceEventVector found;
+ analyzer->FindEvents(Query::Bool(true), &found);
+ EXPECT_EQ(0u, found.size());
+}
+
+TEST_F(TraceEventAnalyzerTest, TraceEvent) {
+ ManualSetUp();
+
+ int int_num = 2;
+ double double_num = 3.5;
+ const char str[] = "the string";
+
+ TraceEvent event;
+ event.arg_numbers["false"] = 0.0;
+ event.arg_numbers["true"] = 1.0;
+ event.arg_numbers["int"] = static_cast<double>(int_num);
+ event.arg_numbers["double"] = double_num;
+ event.arg_strings["string"] = str;
+ event.arg_values["dict"] = std::make_unique<base::DictionaryValue>();
+
+ ASSERT_TRUE(event.HasNumberArg("false"));
+ ASSERT_TRUE(event.HasNumberArg("true"));
+ ASSERT_TRUE(event.HasNumberArg("int"));
+ ASSERT_TRUE(event.HasNumberArg("double"));
+ ASSERT_TRUE(event.HasStringArg("string"));
+ ASSERT_FALSE(event.HasNumberArg("notfound"));
+ ASSERT_FALSE(event.HasStringArg("notfound"));
+ ASSERT_TRUE(event.HasArg("dict"));
+ ASSERT_FALSE(event.HasArg("notfound"));
+
+ EXPECT_FALSE(event.GetKnownArgAsBool("false"));
+ EXPECT_TRUE(event.GetKnownArgAsBool("true"));
+ EXPECT_EQ(int_num, event.GetKnownArgAsInt("int"));
+ EXPECT_EQ(double_num, event.GetKnownArgAsDouble("double"));
+ EXPECT_STREQ(str, event.GetKnownArgAsString("string").c_str());
+
+ std::unique_ptr<base::Value> arg;
+ EXPECT_TRUE(event.GetArgAsValue("dict", &arg));
+ EXPECT_EQ(base::Value::Type::DICTIONARY, arg->type());
+}
+
+TEST_F(TraceEventAnalyzerTest, QueryEventMember) {
+ ManualSetUp();
+
+ TraceEvent event;
+ event.thread.process_id = 3;
+ event.thread.thread_id = 4;
+ event.timestamp = 1.5;
+ event.phase = TRACE_EVENT_PHASE_BEGIN;
+ event.category = "category";
+ event.name = "name";
+ event.id = "1";
+ event.arg_numbers["num"] = 7.0;
+ event.arg_strings["str"] = "the string";
+
+ // Other event with all different members:
+ TraceEvent other;
+ other.thread.process_id = 5;
+ other.thread.thread_id = 6;
+ other.timestamp = 2.5;
+ other.phase = TRACE_EVENT_PHASE_END;
+ other.category = "category2";
+ other.name = "name2";
+ other.id = "2";
+ other.arg_numbers["num2"] = 8.0;
+ other.arg_strings["str2"] = "the string 2";
+
+ event.other_event = &other;
+ ASSERT_TRUE(event.has_other_event());
+ double duration = event.GetAbsTimeToOtherEvent();
+
+ Query event_pid = Query::EventPidIs(event.thread.process_id);
+ Query event_tid = Query::EventTidIs(event.thread.thread_id);
+ Query event_time = Query::EventTimeIs(event.timestamp);
+ Query event_duration = Query::EventDurationIs(duration);
+ Query event_phase = Query::EventPhaseIs(event.phase);
+ Query event_category = Query::EventCategoryIs(event.category);
+ Query event_name = Query::EventNameIs(event.name);
+ Query event_id = Query::EventIdIs(event.id);
+ Query event_has_arg1 = Query::EventHasNumberArg("num");
+ Query event_has_arg2 = Query::EventHasStringArg("str");
+ Query event_arg1 =
+ (Query::EventArg("num") == Query::Double(event.arg_numbers["num"]));
+ Query event_arg2 =
+ (Query::EventArg("str") == Query::String(event.arg_strings["str"]));
+ Query event_has_other = Query::EventHasOther();
+ Query other_pid = Query::OtherPidIs(other.thread.process_id);
+ Query other_tid = Query::OtherTidIs(other.thread.thread_id);
+ Query other_time = Query::OtherTimeIs(other.timestamp);
+ Query other_phase = Query::OtherPhaseIs(other.phase);
+ Query other_category = Query::OtherCategoryIs(other.category);
+ Query other_name = Query::OtherNameIs(other.name);
+ Query other_id = Query::OtherIdIs(other.id);
+ Query other_has_arg1 = Query::OtherHasNumberArg("num2");
+ Query other_has_arg2 = Query::OtherHasStringArg("str2");
+ Query other_arg1 =
+ (Query::OtherArg("num2") == Query::Double(other.arg_numbers["num2"]));
+ Query other_arg2 =
+ (Query::OtherArg("str2") == Query::String(other.arg_strings["str2"]));
+
+ EXPECT_TRUE(event_pid.Evaluate(event));
+ EXPECT_TRUE(event_tid.Evaluate(event));
+ EXPECT_TRUE(event_time.Evaluate(event));
+ EXPECT_TRUE(event_duration.Evaluate(event));
+ EXPECT_TRUE(event_phase.Evaluate(event));
+ EXPECT_TRUE(event_category.Evaluate(event));
+ EXPECT_TRUE(event_name.Evaluate(event));
+ EXPECT_TRUE(event_id.Evaluate(event));
+ EXPECT_TRUE(event_has_arg1.Evaluate(event));
+ EXPECT_TRUE(event_has_arg2.Evaluate(event));
+ EXPECT_TRUE(event_arg1.Evaluate(event));
+ EXPECT_TRUE(event_arg2.Evaluate(event));
+ EXPECT_TRUE(event_has_other.Evaluate(event));
+ EXPECT_TRUE(other_pid.Evaluate(event));
+ EXPECT_TRUE(other_tid.Evaluate(event));
+ EXPECT_TRUE(other_time.Evaluate(event));
+ EXPECT_TRUE(other_phase.Evaluate(event));
+ EXPECT_TRUE(other_category.Evaluate(event));
+ EXPECT_TRUE(other_name.Evaluate(event));
+ EXPECT_TRUE(other_id.Evaluate(event));
+ EXPECT_TRUE(other_has_arg1.Evaluate(event));
+ EXPECT_TRUE(other_has_arg2.Evaluate(event));
+ EXPECT_TRUE(other_arg1.Evaluate(event));
+ EXPECT_TRUE(other_arg2.Evaluate(event));
+
+ // Evaluate event queries against other to verify the queries fail when the
+ // event members are wrong.
+ EXPECT_FALSE(event_pid.Evaluate(other));
+ EXPECT_FALSE(event_tid.Evaluate(other));
+ EXPECT_FALSE(event_time.Evaluate(other));
+ EXPECT_FALSE(event_duration.Evaluate(other));
+ EXPECT_FALSE(event_phase.Evaluate(other));
+ EXPECT_FALSE(event_category.Evaluate(other));
+ EXPECT_FALSE(event_name.Evaluate(other));
+ EXPECT_FALSE(event_id.Evaluate(other));
+ EXPECT_FALSE(event_has_arg1.Evaluate(other));
+ EXPECT_FALSE(event_has_arg2.Evaluate(other));
+ EXPECT_FALSE(event_arg1.Evaluate(other));
+ EXPECT_FALSE(event_arg2.Evaluate(other));
+ EXPECT_FALSE(event_has_other.Evaluate(other));
+}
+
+TEST_F(TraceEventAnalyzerTest, BooleanOperators) {
+ ManualSetUp();
+
+ BeginTracing();
+ {
+ TRACE_EVENT_INSTANT1("cat1", "name1", TRACE_EVENT_SCOPE_THREAD, "num", 1);
+ TRACE_EVENT_INSTANT1("cat1", "name2", TRACE_EVENT_SCOPE_THREAD, "num", 2);
+ TRACE_EVENT_INSTANT1("cat2", "name3", TRACE_EVENT_SCOPE_THREAD, "num", 3);
+ TRACE_EVENT_INSTANT1("cat2", "name4", TRACE_EVENT_SCOPE_THREAD, "num", 4);
+ }
+ EndTracing();
+
+ std::unique_ptr<TraceAnalyzer> analyzer(
+ TraceAnalyzer::Create(output_.json_output));
+ ASSERT_TRUE(analyzer);
+ analyzer->SetIgnoreMetadataEvents(true);
+
+ TraceEventVector found;
+
+ // ==
+
+ analyzer->FindEvents(Query::EventCategory() == Query::String("cat1"), &found);
+ ASSERT_EQ(2u, found.size());
+ EXPECT_STREQ("name1", found[0]->name.c_str());
+ EXPECT_STREQ("name2", found[1]->name.c_str());
+
+ analyzer->FindEvents(Query::EventArg("num") == Query::Int(2), &found);
+ ASSERT_EQ(1u, found.size());
+ EXPECT_STREQ("name2", found[0]->name.c_str());
+
+ // !=
+
+ analyzer->FindEvents(Query::EventCategory() != Query::String("cat1"), &found);
+ ASSERT_EQ(2u, found.size());
+ EXPECT_STREQ("name3", found[0]->name.c_str());
+ EXPECT_STREQ("name4", found[1]->name.c_str());
+
+ analyzer->FindEvents(Query::EventArg("num") != Query::Int(2), &found);
+ ASSERT_EQ(3u, found.size());
+ EXPECT_STREQ("name1", found[0]->name.c_str());
+ EXPECT_STREQ("name3", found[1]->name.c_str());
+ EXPECT_STREQ("name4", found[2]->name.c_str());
+
+ // <
+ analyzer->FindEvents(Query::EventArg("num") < Query::Int(2), &found);
+ ASSERT_EQ(1u, found.size());
+ EXPECT_STREQ("name1", found[0]->name.c_str());
+
+ // <=
+ analyzer->FindEvents(Query::EventArg("num") <= Query::Int(2), &found);
+ ASSERT_EQ(2u, found.size());
+ EXPECT_STREQ("name1", found[0]->name.c_str());
+ EXPECT_STREQ("name2", found[1]->name.c_str());
+
+ // >
+ analyzer->FindEvents(Query::EventArg("num") > Query::Int(3), &found);
+ ASSERT_EQ(1u, found.size());
+ EXPECT_STREQ("name4", found[0]->name.c_str());
+
+ // >=
+ analyzer->FindEvents(Query::EventArg("num") >= Query::Int(4), &found);
+ ASSERT_EQ(1u, found.size());
+ EXPECT_STREQ("name4", found[0]->name.c_str());
+
+ // &&
+ analyzer->FindEvents(Query::EventName() != Query::String("name1") &&
+ Query::EventArg("num") < Query::Int(3), &found);
+ ASSERT_EQ(1u, found.size());
+ EXPECT_STREQ("name2", found[0]->name.c_str());
+
+ // ||
+ analyzer->FindEvents(Query::EventName() == Query::String("name1") ||
+ Query::EventArg("num") == Query::Int(3), &found);
+ ASSERT_EQ(2u, found.size());
+ EXPECT_STREQ("name1", found[0]->name.c_str());
+ EXPECT_STREQ("name3", found[1]->name.c_str());
+
+ // !
+ analyzer->FindEvents(!(Query::EventName() == Query::String("name1") ||
+ Query::EventArg("num") == Query::Int(3)), &found);
+ ASSERT_EQ(2u, found.size());
+ EXPECT_STREQ("name2", found[0]->name.c_str());
+ EXPECT_STREQ("name4", found[1]->name.c_str());
+}
+
+TEST_F(TraceEventAnalyzerTest, ArithmeticOperators) {
+ ManualSetUp();
+
+ BeginTracing();
+ {
+ // These events are searched for:
+ TRACE_EVENT_INSTANT2("cat1", "math1", TRACE_EVENT_SCOPE_THREAD,
+ "a", 10, "b", 5);
+ TRACE_EVENT_INSTANT2("cat1", "math2", TRACE_EVENT_SCOPE_THREAD,
+ "a", 10, "b", 10);
+ // Extra events that never match, for noise:
+ TRACE_EVENT_INSTANT2("noise", "math3", TRACE_EVENT_SCOPE_THREAD,
+ "a", 1, "b", 3);
+ TRACE_EVENT_INSTANT2("noise", "math4", TRACE_EVENT_SCOPE_THREAD,
+ "c", 10, "d", 5);
+ }
+ EndTracing();
+
+ std::unique_ptr<TraceAnalyzer> analyzer(
+ TraceAnalyzer::Create(output_.json_output));
+ ASSERT_TRUE(analyzer.get());
+
+ TraceEventVector found;
+
+ // Verify that arithmetic operators function:
+
+ // +
+ analyzer->FindEvents(Query::EventArg("a") + Query::EventArg("b") ==
+ Query::Int(20), &found);
+ EXPECT_EQ(1u, found.size());
+ EXPECT_STREQ("math2", found.front()->name.c_str());
+
+ // -
+ analyzer->FindEvents(Query::EventArg("a") - Query::EventArg("b") ==
+ Query::Int(5), &found);
+ EXPECT_EQ(1u, found.size());
+ EXPECT_STREQ("math1", found.front()->name.c_str());
+
+ // *
+ analyzer->FindEvents(Query::EventArg("a") * Query::EventArg("b") ==
+ Query::Int(50), &found);
+ EXPECT_EQ(1u, found.size());
+ EXPECT_STREQ("math1", found.front()->name.c_str());
+
+ // /
+ analyzer->FindEvents(Query::EventArg("a") / Query::EventArg("b") ==
+ Query::Int(2), &found);
+ EXPECT_EQ(1u, found.size());
+ EXPECT_STREQ("math1", found.front()->name.c_str());
+
+ // %
+ analyzer->FindEvents(Query::EventArg("a") % Query::EventArg("b") ==
+ Query::Int(0), &found);
+ EXPECT_EQ(2u, found.size());
+
+ // - (negate)
+ analyzer->FindEvents(-Query::EventArg("b") == Query::Int(-10), &found);
+ EXPECT_EQ(1u, found.size());
+ EXPECT_STREQ("math2", found.front()->name.c_str());
+}
+
+TEST_F(TraceEventAnalyzerTest, StringPattern) {
+ ManualSetUp();
+
+ BeginTracing();
+ {
+ TRACE_EVENT_INSTANT0("cat1", "name1", TRACE_EVENT_SCOPE_THREAD);
+ TRACE_EVENT_INSTANT0("cat1", "name2", TRACE_EVENT_SCOPE_THREAD);
+ TRACE_EVENT_INSTANT0("cat1", "no match", TRACE_EVENT_SCOPE_THREAD);
+ TRACE_EVENT_INSTANT0("cat1", "name3x", TRACE_EVENT_SCOPE_THREAD);
+ }
+ EndTracing();
+
+ std::unique_ptr<TraceAnalyzer> analyzer(
+ TraceAnalyzer::Create(output_.json_output));
+ ASSERT_TRUE(analyzer.get());
+ analyzer->SetIgnoreMetadataEvents(true);
+
+ TraceEventVector found;
+
+ analyzer->FindEvents(Query::EventName() == Query::Pattern("name?"), &found);
+ ASSERT_EQ(2u, found.size());
+ EXPECT_STREQ("name1", found[0]->name.c_str());
+ EXPECT_STREQ("name2", found[1]->name.c_str());
+
+ analyzer->FindEvents(Query::EventName() == Query::Pattern("name*"), &found);
+ ASSERT_EQ(3u, found.size());
+ EXPECT_STREQ("name1", found[0]->name.c_str());
+ EXPECT_STREQ("name2", found[1]->name.c_str());
+ EXPECT_STREQ("name3x", found[2]->name.c_str());
+
+ analyzer->FindEvents(Query::EventName() != Query::Pattern("name*"), &found);
+ ASSERT_EQ(1u, found.size());
+ EXPECT_STREQ("no match", found[0]->name.c_str());
+}
+
+// Test that duration queries work.
+TEST_F(TraceEventAnalyzerTest, BeginEndDuration) {
+ ManualSetUp();
+
+ const base::TimeDelta kSleepTime = base::TimeDelta::FromMilliseconds(200);
+ // We will search for events that have a duration of greater than 90% of the
+ // sleep time, so that there is no flakiness.
+ int64_t duration_cutoff_us = (kSleepTime.InMicroseconds() * 9) / 10;
+
+ BeginTracing();
+ {
+ TRACE_EVENT_BEGIN0("cat1", "name1"); // found by duration query
+ TRACE_EVENT_BEGIN0("noise", "name2"); // not searched for, just noise
+ {
+ TRACE_EVENT_BEGIN0("cat2", "name3"); // found by duration query
+ // next event not searched for, just noise
+ TRACE_EVENT_INSTANT0("noise", "name4", TRACE_EVENT_SCOPE_THREAD);
+ base::PlatformThread::Sleep(kSleepTime);
+ TRACE_EVENT_BEGIN0("cat2", "name5"); // not found (duration too short)
+ TRACE_EVENT_END0("cat2", "name5"); // not found (duration too short)
+ TRACE_EVENT_END0("cat2", "name3"); // found by duration query
+ }
+ TRACE_EVENT_END0("noise", "name2"); // not searched for, just noise
+ TRACE_EVENT_END0("cat1", "name1"); // found by duration query
+ }
+ EndTracing();
+
+ std::unique_ptr<TraceAnalyzer> analyzer(
+ TraceAnalyzer::Create(output_.json_output));
+ ASSERT_TRUE(analyzer.get());
+ analyzer->AssociateBeginEndEvents();
+
+ TraceEventVector found;
+ analyzer->FindEvents(
+ Query::MatchBeginWithEnd() &&
+ Query::EventDuration() >
+ Query::Int(static_cast<int>(duration_cutoff_us)) &&
+ (Query::EventCategory() == Query::String("cat1") ||
+ Query::EventCategory() == Query::String("cat2") ||
+ Query::EventCategory() == Query::String("cat3")),
+ &found);
+ ASSERT_EQ(2u, found.size());
+ EXPECT_STREQ("name1", found[0]->name.c_str());
+ EXPECT_STREQ("name3", found[1]->name.c_str());
+}
+
+// Test that duration queries work.
+TEST_F(TraceEventAnalyzerTest, CompleteDuration) {
+ ManualSetUp();
+
+ const base::TimeDelta kSleepTime = base::TimeDelta::FromMilliseconds(200);
+ // We will search for events that have a duration of greater than 90% of the
+ // sleep time, so that there is no flakiness.
+ int64_t duration_cutoff_us = (kSleepTime.InMicroseconds() * 9) / 10;
+
+ BeginTracing();
+ {
+ TRACE_EVENT0("cat1", "name1"); // found by duration query
+ TRACE_EVENT0("noise", "name2"); // not searched for, just noise
+ {
+ TRACE_EVENT0("cat2", "name3"); // found by duration query
+ // next event not searched for, just noise
+ TRACE_EVENT_INSTANT0("noise", "name4", TRACE_EVENT_SCOPE_THREAD);
+ base::PlatformThread::Sleep(kSleepTime);
+ TRACE_EVENT0("cat2", "name5"); // not found (duration too short)
+ }
+ }
+ EndTracing();
+
+ std::unique_ptr<TraceAnalyzer> analyzer(
+ TraceAnalyzer::Create(output_.json_output));
+ ASSERT_TRUE(analyzer.get());
+ analyzer->AssociateBeginEndEvents();
+
+ TraceEventVector found;
+ analyzer->FindEvents(
+ Query::EventCompleteDuration() >
+ Query::Int(static_cast<int>(duration_cutoff_us)) &&
+ (Query::EventCategory() == Query::String("cat1") ||
+ Query::EventCategory() == Query::String("cat2") ||
+ Query::EventCategory() == Query::String("cat3")),
+ &found);
+ ASSERT_EQ(2u, found.size());
+ EXPECT_STREQ("name1", found[0]->name.c_str());
+ EXPECT_STREQ("name3", found[1]->name.c_str());
+}
+
+// Test AssociateBeginEndEvents
+TEST_F(TraceEventAnalyzerTest, BeginEndAssocations) {
+ ManualSetUp();
+
+ BeginTracing();
+ {
+ TRACE_EVENT_END0("cat1", "name1"); // does not match out of order begin
+ TRACE_EVENT_BEGIN0("cat1", "name2");
+ TRACE_EVENT_INSTANT0("cat1", "name3", TRACE_EVENT_SCOPE_THREAD);
+ TRACE_EVENT_BEGIN0("cat1", "name1");
+ TRACE_EVENT_END0("cat1", "name2");
+ }
+ EndTracing();
+
+ std::unique_ptr<TraceAnalyzer> analyzer(
+ TraceAnalyzer::Create(output_.json_output));
+ ASSERT_TRUE(analyzer.get());
+ analyzer->AssociateBeginEndEvents();
+
+ TraceEventVector found;
+ analyzer->FindEvents(Query::MatchBeginWithEnd(), &found);
+ ASSERT_EQ(1u, found.size());
+ EXPECT_STREQ("name2", found[0]->name.c_str());
+}
+
+// Test MergeAssociatedEventArgs
+TEST_F(TraceEventAnalyzerTest, MergeAssociatedEventArgs) {
+ ManualSetUp();
+
+ const char arg_string[] = "arg_string";
+ BeginTracing();
+ {
+ TRACE_EVENT_BEGIN0("cat1", "name1");
+ TRACE_EVENT_END1("cat1", "name1", "arg", arg_string);
+ }
+ EndTracing();
+
+ std::unique_ptr<TraceAnalyzer> analyzer(
+ TraceAnalyzer::Create(output_.json_output));
+ ASSERT_TRUE(analyzer.get());
+ analyzer->AssociateBeginEndEvents();
+
+ TraceEventVector found;
+ analyzer->FindEvents(Query::MatchBeginName("name1"), &found);
+ ASSERT_EQ(1u, found.size());
+ std::string arg_actual;
+ EXPECT_FALSE(found[0]->GetArgAsString("arg", &arg_actual));
+
+ analyzer->MergeAssociatedEventArgs();
+ EXPECT_TRUE(found[0]->GetArgAsString("arg", &arg_actual));
+ EXPECT_STREQ(arg_string, arg_actual.c_str());
+}
+
+// Test AssociateAsyncBeginEndEvents
+TEST_F(TraceEventAnalyzerTest, AsyncBeginEndAssocations) {
+ ManualSetUp();
+
+ BeginTracing();
+ {
+ TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xA); // no match / out of order
+ TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xB);
+ TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xC);
+ TRACE_EVENT_INSTANT0("cat1", "name1", TRACE_EVENT_SCOPE_THREAD); // noise
+ TRACE_EVENT0("cat1", "name1"); // noise
+ TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xB);
+ TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xC);
+ TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xA); // no match / out of order
+ }
+ EndTracing();
+
+ std::unique_ptr<TraceAnalyzer> analyzer(
+ TraceAnalyzer::Create(output_.json_output));
+ ASSERT_TRUE(analyzer.get());
+ analyzer->AssociateAsyncBeginEndEvents();
+
+ TraceEventVector found;
+ analyzer->FindEvents(Query::MatchAsyncBeginWithNext(), &found);
+ ASSERT_EQ(2u, found.size());
+ EXPECT_STRCASEEQ("0xb", found[0]->id.c_str());
+ EXPECT_STRCASEEQ("0xc", found[1]->id.c_str());
+}
+
+// Test AssociateAsyncBeginEndEvents
+TEST_F(TraceEventAnalyzerTest, AsyncBeginEndAssocationsWithSteps) {
+ ManualSetUp();
+
+ BeginTracing();
+ {
+ TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xA, "s1");
+ TRACE_EVENT_ASYNC_END0("c", "n", 0xA);
+ TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xB);
+ TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xC);
+ TRACE_EVENT_ASYNC_STEP_PAST0("c", "n", 0xB, "s1");
+ TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xC, "s1");
+ TRACE_EVENT_ASYNC_STEP_INTO1("c", "n", 0xC, "s2", "a", 1);
+ TRACE_EVENT_ASYNC_END0("c", "n", 0xB);
+ TRACE_EVENT_ASYNC_END0("c", "n", 0xC);
+ TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xA);
+ TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xA, "s2");
+ }
+ EndTracing();
+
+ std::unique_ptr<TraceAnalyzer> analyzer(
+ TraceAnalyzer::Create(output_.json_output));
+ ASSERT_TRUE(analyzer.get());
+ analyzer->AssociateAsyncBeginEndEvents();
+
+ TraceEventVector found;
+ analyzer->FindEvents(Query::MatchAsyncBeginWithNext(), &found);
+ ASSERT_EQ(3u, found.size());
+
+ EXPECT_STRCASEEQ("0xb", found[0]->id.c_str());
+ EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, found[0]->other_event->phase);
+ EXPECT_EQ(found[0], found[0]->other_event->prev_event);
+ EXPECT_TRUE(found[0]->other_event->other_event);
+ EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_END,
+ found[0]->other_event->other_event->phase);
+ EXPECT_EQ(found[0]->other_event,
+ found[0]->other_event->other_event->prev_event);
+
+ EXPECT_STRCASEEQ("0xc", found[1]->id.c_str());
+ EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, found[1]->other_event->phase);
+ EXPECT_EQ(found[1], found[1]->other_event->prev_event);
+ EXPECT_TRUE(found[1]->other_event->other_event);
+ EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO,
+ found[1]->other_event->other_event->phase);
+ EXPECT_EQ(found[1]->other_event,
+ found[1]->other_event->other_event->prev_event);
+ double arg_actual = 0;
+ EXPECT_TRUE(found[1]->other_event->other_event->GetArgAsNumber(
+ "a", &arg_actual));
+ EXPECT_EQ(1.0, arg_actual);
+ EXPECT_TRUE(found[1]->other_event->other_event->other_event);
+ EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_END,
+ found[1]->other_event->other_event->other_event->phase);
+
+ EXPECT_STRCASEEQ("0xa", found[2]->id.c_str());
+ EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, found[2]->other_event->phase);
+}
+
+// Test that the TraceAnalyzer custom associations work.
+TEST_F(TraceEventAnalyzerTest, CustomAssociations) {
+ ManualSetUp();
+
+ // Add events that begin/end in pipelined ordering with unique ID parameter
+ // to match up the begin/end pairs.
+ BeginTracing();
+ {
+ // no begin match
+ TRACE_EVENT_INSTANT1("cat1", "end", TRACE_EVENT_SCOPE_THREAD, "id", 1);
+ // end is cat4
+ TRACE_EVENT_INSTANT1("cat2", "begin", TRACE_EVENT_SCOPE_THREAD, "id", 2);
+ // end is cat5
+ TRACE_EVENT_INSTANT1("cat3", "begin", TRACE_EVENT_SCOPE_THREAD, "id", 3);
+ TRACE_EVENT_INSTANT1("cat4", "end", TRACE_EVENT_SCOPE_THREAD, "id", 2);
+ TRACE_EVENT_INSTANT1("cat5", "end", TRACE_EVENT_SCOPE_THREAD, "id", 3);
+ // no end match
+ TRACE_EVENT_INSTANT1("cat6", "begin", TRACE_EVENT_SCOPE_THREAD, "id", 1);
+ }
+ EndTracing();
+
+ std::unique_ptr<TraceAnalyzer> analyzer(
+ TraceAnalyzer::Create(output_.json_output));
+ ASSERT_TRUE(analyzer.get());
+
+ // begin, end, and match queries to find proper begin/end pairs.
+ Query begin(Query::EventName() == Query::String("begin"));
+ Query end(Query::EventName() == Query::String("end"));
+ Query match(Query::EventArg("id") == Query::OtherArg("id"));
+ analyzer->AssociateEvents(begin, end, match);
+
+ TraceEventVector found;
+
+ // cat1 has no other_event.
+ analyzer->FindEvents(Query::EventCategory() == Query::String("cat1") &&
+ Query::EventHasOther(), &found);
+ EXPECT_EQ(0u, found.size());
+
+ // cat1 has no other_event.
+ analyzer->FindEvents(Query::EventCategory() == Query::String("cat1") &&
+ !Query::EventHasOther(), &found);
+ EXPECT_EQ(1u, found.size());
+
+ // cat6 has no other_event.
+ analyzer->FindEvents(Query::EventCategory() == Query::String("cat6") &&
+ !Query::EventHasOther(), &found);
+ EXPECT_EQ(1u, found.size());
+
+ // cat2 and cat4 are associated.
+ analyzer->FindEvents(Query::EventCategory() == Query::String("cat2") &&
+ Query::OtherCategory() == Query::String("cat4"), &found);
+ EXPECT_EQ(1u, found.size());
+
+ // cat4 and cat2 are not associated.
+ analyzer->FindEvents(Query::EventCategory() == Query::String("cat4") &&
+ Query::OtherCategory() == Query::String("cat2"), &found);
+ EXPECT_EQ(0u, found.size());
+
+ // cat3 and cat5 are associated.
+ analyzer->FindEvents(Query::EventCategory() == Query::String("cat3") &&
+ Query::OtherCategory() == Query::String("cat5"), &found);
+ EXPECT_EQ(1u, found.size());
+
+ // cat5 and cat3 are not associated.
+ analyzer->FindEvents(Query::EventCategory() == Query::String("cat5") &&
+ Query::OtherCategory() == Query::String("cat3"), &found);
+ EXPECT_EQ(0u, found.size());
+}
+
+// Verify that Query literals and types are properly casted.
+TEST_F(TraceEventAnalyzerTest, Literals) {
+ ManualSetUp();
+
+ // Since these queries don't refer to the event data, the dummy event below
+ // will never be accessed.
+ TraceEvent dummy;
+ char char_num = 5;
+ short short_num = -5;
+ EXPECT_TRUE((Query::Double(5.0) == Query::Int(char_num)).Evaluate(dummy));
+ EXPECT_TRUE((Query::Double(-5.0) == Query::Int(short_num)).Evaluate(dummy));
+ EXPECT_TRUE((Query::Double(1.0) == Query::Uint(1u)).Evaluate(dummy));
+ EXPECT_TRUE((Query::Double(1.0) == Query::Int(1)).Evaluate(dummy));
+ EXPECT_TRUE((Query::Double(-1.0) == Query::Int(-1)).Evaluate(dummy));
+ EXPECT_TRUE((Query::Double(1.0) == Query::Double(1.0f)).Evaluate(dummy));
+ EXPECT_TRUE((Query::Bool(true) == Query::Int(1)).Evaluate(dummy));
+ EXPECT_TRUE((Query::Bool(false) == Query::Int(0)).Evaluate(dummy));
+ EXPECT_TRUE((Query::Bool(true) == Query::Double(1.0f)).Evaluate(dummy));
+ EXPECT_TRUE((Query::Bool(false) == Query::Double(0.0f)).Evaluate(dummy));
+}
+
+// Test GetRateStats.
+TEST_F(TraceEventAnalyzerTest, RateStats) {
+ std::vector<TraceEvent> events;
+ events.reserve(100);
+ TraceEventVector event_ptrs;
+ double timestamp = 0.0;
+ double little_delta = 1.0;
+ double big_delta = 10.0;
+ double tiny_delta = 0.1;
+ RateStats stats;
+ RateStatsOptions options;
+
+ // Insert 10 events, each apart by little_delta.
+ for (int i = 0; i < 10; ++i) {
+ timestamp += little_delta;
+ TraceEvent event;
+ event.timestamp = timestamp;
+ events.push_back(std::move(event));
+ event_ptrs.push_back(&events.back());
+ }
+
+ ASSERT_TRUE(GetRateStats(event_ptrs, &stats, nullptr));
+ EXPECT_EQ(little_delta, stats.mean_us);
+ EXPECT_EQ(little_delta, stats.min_us);
+ EXPECT_EQ(little_delta, stats.max_us);
+ EXPECT_EQ(0.0, stats.standard_deviation_us);
+
+ // Add an event apart by big_delta.
+ {
+ timestamp += big_delta;
+ TraceEvent event;
+ event.timestamp = timestamp;
+ events.push_back(std::move(event));
+ event_ptrs.push_back(&events.back());
+ }
+
+ ASSERT_TRUE(GetRateStats(event_ptrs, &stats, nullptr));
+ EXPECT_LT(little_delta, stats.mean_us);
+ EXPECT_EQ(little_delta, stats.min_us);
+ EXPECT_EQ(big_delta, stats.max_us);
+ EXPECT_LT(0.0, stats.standard_deviation_us);
+
+ // Trim off the biggest delta and verify stats.
+ options.trim_min = 0;
+ options.trim_max = 1;
+ ASSERT_TRUE(GetRateStats(event_ptrs, &stats, &options));
+ EXPECT_EQ(little_delta, stats.mean_us);
+ EXPECT_EQ(little_delta, stats.min_us);
+ EXPECT_EQ(little_delta, stats.max_us);
+ EXPECT_EQ(0.0, stats.standard_deviation_us);
+
+ // Add an event apart by tiny_delta.
+ {
+ timestamp += tiny_delta;
+ TraceEvent event;
+ event.timestamp = timestamp;
+ events.push_back(std::move(event));
+ event_ptrs.push_back(&events.back());
+ }
+
+ // Trim off both the biggest and tiniest delta and verify stats.
+ options.trim_min = 1;
+ options.trim_max = 1;
+ ASSERT_TRUE(GetRateStats(event_ptrs, &stats, &options));
+ EXPECT_EQ(little_delta, stats.mean_us);
+ EXPECT_EQ(little_delta, stats.min_us);
+ EXPECT_EQ(little_delta, stats.max_us);
+ EXPECT_EQ(0.0, stats.standard_deviation_us);
+
+ // Verify smallest allowed number of events.
+ {
+ TraceEvent event;
+ TraceEventVector few_event_ptrs;
+ few_event_ptrs.push_back(&event);
+ few_event_ptrs.push_back(&event);
+ ASSERT_FALSE(GetRateStats(few_event_ptrs, &stats, nullptr));
+ few_event_ptrs.push_back(&event);
+ ASSERT_TRUE(GetRateStats(few_event_ptrs, &stats, nullptr));
+
+ // Trim off more than allowed and verify failure.
+ options.trim_min = 0;
+ options.trim_max = 1;
+ ASSERT_FALSE(GetRateStats(few_event_ptrs, &stats, &options));
+ }
+}
+
+// Test FindFirstOf and FindLastOf.
+TEST_F(TraceEventAnalyzerTest, FindOf) {
+ size_t num_events = 100;
+ size_t index = 0;
+ TraceEventVector event_ptrs;
+ EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(true), 0, &index));
+ EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(true), 10, &index));
+ EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(true), 0, &index));
+ EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(true), 10, &index));
+
+ std::vector<TraceEvent> events;
+ events.resize(num_events);
+ for (auto& i : events)
+ event_ptrs.push_back(&i);
+ size_t bam_index = num_events/2;
+ events[bam_index].name = "bam";
+ Query query_bam = Query::EventName() == Query::String(events[bam_index].name);
+
+ // FindFirstOf
+ EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(false), 0, &index));
+ EXPECT_TRUE(FindFirstOf(event_ptrs, Query::Bool(true), 0, &index));
+ EXPECT_EQ(0u, index);
+ EXPECT_TRUE(FindFirstOf(event_ptrs, Query::Bool(true), 5, &index));
+ EXPECT_EQ(5u, index);
+
+ EXPECT_FALSE(FindFirstOf(event_ptrs, query_bam, bam_index + 1, &index));
+ EXPECT_TRUE(FindFirstOf(event_ptrs, query_bam, 0, &index));
+ EXPECT_EQ(bam_index, index);
+ EXPECT_TRUE(FindFirstOf(event_ptrs, query_bam, bam_index, &index));
+ EXPECT_EQ(bam_index, index);
+
+ // FindLastOf
+ EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(false), 1000, &index));
+ EXPECT_TRUE(FindLastOf(event_ptrs, Query::Bool(true), 1000, &index));
+ EXPECT_EQ(num_events - 1, index);
+ EXPECT_TRUE(FindLastOf(event_ptrs, Query::Bool(true), num_events - 5,
+ &index));
+ EXPECT_EQ(num_events - 5, index);
+
+ EXPECT_FALSE(FindLastOf(event_ptrs, query_bam, bam_index - 1, &index));
+ EXPECT_TRUE(FindLastOf(event_ptrs, query_bam, num_events, &index));
+ EXPECT_EQ(bam_index, index);
+ EXPECT_TRUE(FindLastOf(event_ptrs, query_bam, bam_index, &index));
+ EXPECT_EQ(bam_index, index);
+}
+
+// Test FindClosest.
+TEST_F(TraceEventAnalyzerTest, FindClosest) {
+ size_t index_1 = 0;
+ size_t index_2 = 0;
+ TraceEventVector event_ptrs;
+ EXPECT_FALSE(FindClosest(event_ptrs, Query::Bool(true), 0,
+ &index_1, &index_2));
+
+ size_t num_events = 5;
+ std::vector<TraceEvent> events;
+ events.resize(num_events);
+ for (size_t i = 0; i < events.size(); ++i) {
+ // timestamps go up exponentially so the lower index is always closer in
+ // time than the higher index.
+ events[i].timestamp = static_cast<double>(i) * static_cast<double>(i);
+ event_ptrs.push_back(&events[i]);
+ }
+ events[0].name = "one";
+ events[2].name = "two";
+ events[4].name = "three";
+ Query query_named = Query::EventName() != Query::String(std::string());
+ Query query_one = Query::EventName() == Query::String("one");
+
+ // Only one event matches query_one, so two closest can't be found.
+ EXPECT_FALSE(FindClosest(event_ptrs, query_one, 0, &index_1, &index_2));
+
+ EXPECT_TRUE(FindClosest(event_ptrs, query_one, 3, &index_1, nullptr));
+ EXPECT_EQ(0u, index_1);
+
+ EXPECT_TRUE(FindClosest(event_ptrs, query_named, 1, &index_1, &index_2));
+ EXPECT_EQ(0u, index_1);
+ EXPECT_EQ(2u, index_2);
+
+ EXPECT_TRUE(FindClosest(event_ptrs, query_named, 4, &index_1, &index_2));
+ EXPECT_EQ(4u, index_1);
+ EXPECT_EQ(2u, index_2);
+
+ EXPECT_TRUE(FindClosest(event_ptrs, query_named, 3, &index_1, &index_2));
+ EXPECT_EQ(2u, index_1);
+ EXPECT_EQ(0u, index_2);
+}
+
+// Test CountMatches.
+TEST_F(TraceEventAnalyzerTest, CountMatches) {
+ TraceEventVector event_ptrs;
+ EXPECT_EQ(0u, CountMatches(event_ptrs, Query::Bool(true), 0, 10));
+
+ size_t num_events = 5;
+ size_t num_named = 3;
+ std::vector<TraceEvent> events;
+ events.resize(num_events);
+ for (auto& i : events)
+ event_ptrs.push_back(&i);
+ events[0].name = "one";
+ events[2].name = "two";
+ events[4].name = "three";
+ Query query_named = Query::EventName() != Query::String(std::string());
+ Query query_one = Query::EventName() == Query::String("one");
+
+ EXPECT_EQ(0u, CountMatches(event_ptrs, Query::Bool(false)));
+ EXPECT_EQ(num_events, CountMatches(event_ptrs, Query::Bool(true)));
+ EXPECT_EQ(num_events - 1, CountMatches(event_ptrs, Query::Bool(true),
+ 1, num_events));
+ EXPECT_EQ(1u, CountMatches(event_ptrs, query_one));
+ EXPECT_EQ(num_events - 1, CountMatches(event_ptrs, !query_one));
+ EXPECT_EQ(num_named, CountMatches(event_ptrs, query_named));
+}
+
+TEST_F(TraceEventAnalyzerTest, ComplexArgument) {
+ ManualSetUp();
+
+ BeginTracing();
+ {
+ std::unique_ptr<base::trace_event::TracedValue> value(
+ new base::trace_event::TracedValue);
+ value->SetString("property", "value");
+ TRACE_EVENT1("cat", "name", "arg", std::move(value));
+ }
+ EndTracing();
+
+ std::unique_ptr<TraceAnalyzer> analyzer(
+ TraceAnalyzer::Create(output_.json_output));
+ ASSERT_TRUE(analyzer.get());
+
+ TraceEventVector events;
+ analyzer->FindEvents(Query::EventName() == Query::String("name"), &events);
+
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ("cat", events[0]->category);
+ EXPECT_EQ("name", events[0]->name);
+ EXPECT_TRUE(events[0]->HasArg("arg"));
+
+ std::unique_ptr<base::Value> arg;
+ events[0]->GetArgAsValue("arg", &arg);
+ base::DictionaryValue* arg_dict;
+ EXPECT_TRUE(arg->GetAsDictionary(&arg_dict));
+ std::string property;
+ EXPECT_TRUE(arg_dict->GetString("property", &property));
+ EXPECT_EQ("value", property);
+}
+
+} // namespace trace_analyzer
diff --git a/chromium/base/test/trace_to_file.cc b/chromium/base/test/trace_to_file.cc
new file mode 100644
index 00000000000..5ada1d00c2a
--- /dev/null
+++ b/chromium/base/test/trace_to_file.cc
@@ -0,0 +1,112 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/trace_to_file.h"
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/trace_buffer.h"
+#include "base/trace_event/trace_log.h"
+
+namespace base {
+namespace test {
+
+TraceToFile::TraceToFile() : started_(false) {
+}
+
+TraceToFile::~TraceToFile() {
+ EndTracingIfNeeded();
+}
+
+void TraceToFile::BeginTracingFromCommandLineOptions() {
+ DCHECK(CommandLine::InitializedForCurrentProcess());
+ DCHECK(!started_);
+
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToFile))
+ return;
+
+ // Empty filter (i.e. just --trace-to-file) turns into default categories in
+ // TraceEventImpl
+ std::string filter = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kTraceToFile);
+
+ FilePath path;
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToFileName)) {
+ path = FilePath(CommandLine::ForCurrentProcess()
+ ->GetSwitchValuePath(switches::kTraceToFileName));
+ } else {
+ path = FilePath(FILE_PATH_LITERAL("trace.json"));
+ }
+
+ BeginTracing(path, filter);
+}
+
+void TraceToFile::BeginTracing(const FilePath& path,
+ const std::string& categories) {
+ DCHECK(!started_);
+ started_ = true;
+ path_ = path;
+ WriteFileHeader();
+
+ trace_event::TraceLog::GetInstance()->SetEnabled(
+ trace_event::TraceConfig(categories, trace_event::RECORD_UNTIL_FULL),
+ trace_event::TraceLog::RECORDING_MODE);
+}
+
+void TraceToFile::WriteFileHeader() {
+ WriteFile(path_, "{\"traceEvents\": [");
+}
+
+void TraceToFile::AppendFileFooter() {
+ const char str[] = "]}";
+ AppendToFile(path_, str, static_cast<int>(strlen(str)));
+}
+
+void TraceToFile::TraceOutputCallback(const std::string& data) {
+ bool ret = AppendToFile(path_, data.c_str(), static_cast<int>(data.size()));
+ DCHECK(ret);
+}
+
+static void OnTraceDataCollected(
+ OnceClosure quit_closure,
+ trace_event::TraceResultBuffer* buffer,
+ const scoped_refptr<RefCountedString>& json_events_str,
+ bool has_more_events) {
+ buffer->AddFragment(json_events_str->data());
+ if (!has_more_events)
+ std::move(quit_closure).Run();
+}
+
+void TraceToFile::EndTracingIfNeeded() {
+ if (!started_)
+ return;
+ started_ = false;
+
+ trace_event::TraceLog::GetInstance()->SetDisabled();
+
+ trace_event::TraceResultBuffer buffer;
+ buffer.SetOutputCallback(
+ BindRepeating(&TraceToFile::TraceOutputCallback, Unretained(this)));
+
+ // In tests we might not have a TaskEnvironment, create one if needed.
+ std::unique_ptr<SingleThreadTaskEnvironment> task_environment;
+ if (!ThreadTaskRunnerHandle::IsSet())
+ task_environment = std::make_unique<SingleThreadTaskEnvironment>();
+
+ RunLoop run_loop;
+ trace_event::TraceLog::GetInstance()->Flush(BindRepeating(
+ &OnTraceDataCollected, run_loop.QuitClosure(), Unretained(&buffer)));
+ run_loop.Run();
+
+ AppendFileFooter();
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/trace_to_file.h b/chromium/base/test/trace_to_file.h
new file mode 100644
index 00000000000..43087367c30
--- /dev/null
+++ b/chromium/base/test/trace_to_file.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TRACE_TO_FILE_H_
+#define BASE_TEST_TRACE_TO_FILE_H_
+
+#include "base/files/file_path.h"
+
+namespace base {
+namespace test {
+
+class TraceToFile {
+ public:
+ TraceToFile();
+ ~TraceToFile();
+
+ void BeginTracingFromCommandLineOptions();
+ void BeginTracing(const base::FilePath& path, const std::string& categories);
+ void EndTracingIfNeeded();
+
+ private:
+ void WriteFileHeader();
+ void AppendFileFooter();
+
+ void TraceOutputCallback(const std::string& data);
+
+ base::FilePath path_;
+ bool started_;
+};
+
+} // namespace test
+} // namespace base
+
+#endif // BASE_TEST_TRACE_TO_FILE_H_
diff --git a/chromium/base/test/values_test_util.cc b/chromium/base/test/values_test_util.cc
new file mode 100644
index 00000000000..5016d5698a2
--- /dev/null
+++ b/chromium/base/test/values_test_util.cc
@@ -0,0 +1,247 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/values_test_util.h"
+
+#include <ostream>
+#include <utility>
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+void ExpectDictBooleanValue(bool expected_value,
+ const DictionaryValue& value,
+ const std::string& key) {
+ bool boolean_value = false;
+ EXPECT_TRUE(value.GetBoolean(key, &boolean_value)) << key;
+ EXPECT_EQ(expected_value, boolean_value) << key;
+}
+
+void ExpectDictDictionaryValue(const DictionaryValue& expected_value,
+ const DictionaryValue& value,
+ const std::string& key) {
+ const DictionaryValue* dict_value = nullptr;
+ EXPECT_TRUE(value.GetDictionary(key, &dict_value)) << key;
+ EXPECT_EQ(expected_value, *dict_value) << key;
+}
+
+void ExpectDictIntegerValue(int expected_value,
+ const DictionaryValue& value,
+ const std::string& key) {
+ int integer_value = 0;
+ EXPECT_TRUE(value.GetInteger(key, &integer_value)) << key;
+ EXPECT_EQ(expected_value, integer_value) << key;
+}
+
+void ExpectDictListValue(const ListValue& expected_value,
+ const DictionaryValue& value,
+ const std::string& key) {
+ const ListValue* list_value = nullptr;
+ EXPECT_TRUE(value.GetList(key, &list_value)) << key;
+ EXPECT_EQ(expected_value, *list_value) << key;
+}
+
+void ExpectDictStringValue(const std::string& expected_value,
+ const DictionaryValue& value,
+ const std::string& key) {
+ std::string string_value;
+ EXPECT_TRUE(value.GetString(key, &string_value)) << key;
+ EXPECT_EQ(expected_value, string_value) << key;
+}
+
+void ExpectStringValue(const std::string& expected_str, const Value& actual) {
+ EXPECT_EQ(Value::Type::STRING, actual.type());
+ EXPECT_EQ(expected_str, actual.GetString());
+}
+
+namespace test {
+
+namespace {
+
+std::string FormatAsJSON(const base::Value& value) {
+ std::string json;
+ JSONWriter::Write(value, &json);
+ return json;
+}
+
+class DictionaryHasValueMatcher
+ : public testing::MatcherInterface<const base::Value&> {
+ public:
+ DictionaryHasValueMatcher(const std::string& key,
+ const base::Value& expected_value)
+ : key_(key), expected_value_(expected_value.Clone()) {}
+
+ ~DictionaryHasValueMatcher() = default;
+
+ bool MatchAndExplain(const base::Value& value,
+ testing::MatchResultListener* listener) const override {
+ if (!value.is_dict()) {
+ *listener << "The value '" << FormatAsJSON(value)
+ << "' is not a dictionary";
+ return false;
+ }
+ const base::Value* sub_value = value.FindKey(key_);
+ if (!sub_value) {
+ *listener << "Dictionary '" << FormatAsJSON(value)
+ << "' does not have key '" << key_ << "'";
+ return false;
+ }
+ if (*sub_value != expected_value_) {
+ *listener << "Dictionary value under key '" << key_ << "' is '"
+ << FormatAsJSON(*sub_value) << "', expected '"
+ << FormatAsJSON(expected_value_) << "'";
+ return false;
+ }
+ return true;
+ }
+
+ void DescribeTo(std::ostream* os) const override {
+ *os << "has key '" << key_ << "' with value '"
+ << FormatAsJSON(expected_value_) << "'";
+ }
+
+ void DescribeNegationTo(std::ostream* os) const override {
+ *os << "does not have key '" << key_ << "' with value '"
+ << FormatAsJSON(expected_value_) << "'";
+ }
+
+ private:
+ DictionaryHasValueMatcher& operator=(const DictionaryHasValueMatcher& other) =
+ delete;
+
+ const std::string key_;
+ const base::Value expected_value_;
+};
+
+class DictionaryHasValuesMatcher
+ : public testing::MatcherInterface<const base::Value&> {
+ public:
+ DictionaryHasValuesMatcher(const base::Value& template_value)
+ : template_value_(template_value.Clone()) {
+ CHECK(template_value.is_dict());
+ }
+
+ ~DictionaryHasValuesMatcher() = default;
+
+ bool MatchAndExplain(const base::Value& value,
+ testing::MatchResultListener* listener) const override {
+ if (!value.is_dict()) {
+ *listener << "The value '" << FormatAsJSON(value)
+ << "' is not a dictionary";
+ return false;
+ }
+
+ bool ok = true;
+ for (const auto& template_dict_item : template_value_.DictItems()) {
+ const base::Value* sub_value = value.FindKey(template_dict_item.first);
+ if (!sub_value) {
+ *listener << "\nDictionary does not have key '"
+ << template_dict_item.first << "'";
+ ok = false;
+ continue;
+ }
+ if (*sub_value != template_dict_item.second) {
+ *listener << "\nDictionary value under key '"
+ << template_dict_item.first << "' is '"
+ << FormatAsJSON(*sub_value) << "', expected '"
+ << FormatAsJSON(template_dict_item.second) << "'";
+ ok = false;
+ }
+ }
+ return ok;
+ }
+
+ void DescribeTo(std::ostream* os) const override {
+ *os << "contains all key-values from '" << FormatAsJSON(template_value_)
+ << "'";
+ }
+
+ void DescribeNegationTo(std::ostream* os) const override {
+ *os << "does not contain key-values from '" << FormatAsJSON(template_value_)
+ << "'";
+ }
+
+ private:
+ DictionaryHasValueMatcher& operator=(const DictionaryHasValueMatcher& other) =
+ delete;
+
+ const base::Value template_value_;
+};
+
+} // namespace
+
+testing::Matcher<const base::Value&> DictionaryHasValue(
+ const std::string& key,
+ const base::Value& expected_value) {
+ return testing::MakeMatcher(
+ new DictionaryHasValueMatcher(key, expected_value));
+}
+
+testing::Matcher<const base::Value&> DictionaryHasValues(
+ const base::Value& template_value) {
+ return testing::MakeMatcher(new DictionaryHasValuesMatcher(template_value));
+}
+
+IsJsonMatcher::IsJsonMatcher(base::StringPiece json)
+ : expected_value_(test::ParseJson(json)) {}
+
+IsJsonMatcher::IsJsonMatcher(const base::Value& value)
+ : expected_value_(value.Clone()) {}
+
+IsJsonMatcher::IsJsonMatcher(const IsJsonMatcher& other)
+ : expected_value_(other.expected_value_.Clone()) {}
+
+IsJsonMatcher::~IsJsonMatcher() = default;
+
+bool IsJsonMatcher::MatchAndExplain(
+ base::StringPiece json,
+ testing::MatchResultListener* listener) const {
+ // This is almost the same logic as ParseJson, but the parser uses stricter
+ // options for JSON data that is assumed to be generated by the code under
+ // test rather than written by hand as part of a unit test.
+ JSONReader::ValueWithError ret =
+ JSONReader::ReadAndReturnValueWithError(json, JSON_PARSE_RFC);
+ if (!ret.value) {
+ *listener << "Failed to parse \"" << json << "\": " << ret.error_message;
+ return false;
+ }
+ return MatchAndExplain(*ret.value, listener);
+}
+
+bool IsJsonMatcher::MatchAndExplain(
+ const base::Value& value,
+ testing::MatchResultListener* /* listener */) const {
+ return expected_value_ == value;
+}
+
+void IsJsonMatcher::DescribeTo(std::ostream* os) const {
+ *os << "is the JSON value " << expected_value_;
+}
+
+void IsJsonMatcher::DescribeNegationTo(std::ostream* os) const {
+ *os << "is not the JSON value " << expected_value_;
+}
+
+Value ParseJson(StringPiece json) {
+ JSONReader::ValueWithError result =
+ JSONReader::ReadAndReturnValueWithError(json, JSON_ALLOW_TRAILING_COMMAS);
+ if (!result.value) {
+ ADD_FAILURE() << "Failed to parse \"" << json
+ << "\": " << result.error_message;
+ return Value();
+ }
+ return std::move(result.value.value());
+}
+
+std::unique_ptr<Value> ParseJsonDeprecated(StringPiece json) {
+ return Value::ToUniquePtrValue(ParseJson(json));
+}
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/values_test_util.h b/chromium/base/test/values_test_util.h
new file mode 100644
index 00000000000..7f48bfd3898
--- /dev/null
+++ b/chromium/base/test/values_test_util.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_VALUES_TEST_UTIL_H_
+#define BASE_TEST_VALUES_TEST_UTIL_H_
+
+#include <iosfwd>
+#include <memory>
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+
+namespace base {
+
+// All the functions below expect that the value for the given key in
+// the given dictionary equals the given expected value.
+
+void ExpectDictBooleanValue(bool expected_value,
+ const DictionaryValue& value,
+ const std::string& key);
+
+void ExpectDictDictionaryValue(const DictionaryValue& expected_value,
+ const DictionaryValue& value,
+ const std::string& key);
+
+void ExpectDictIntegerValue(int expected_value,
+ const DictionaryValue& value,
+ const std::string& key);
+
+void ExpectDictListValue(const ListValue& expected_value,
+ const DictionaryValue& value,
+ const std::string& key);
+
+void ExpectDictStringValue(const std::string& expected_value,
+ const DictionaryValue& value,
+ const std::string& key);
+
+void ExpectStringValue(const std::string& expected_str, const Value& actual);
+
+namespace test {
+
+// A custom GMock matcher which matches if a base::Value is a dictionary which
+// has a key |key| that is equal to |value|.
+testing::Matcher<const base::Value&> DictionaryHasValue(
+ const std::string& key,
+ const base::Value& expected_value);
+
+// A custom GMock matcher which matches if a base::Value is a dictionary which
+// contains all key/value pairs from |template_value|.
+testing::Matcher<const base::Value&> DictionaryHasValues(
+ const base::Value& template_value);
+
+// A custom GMock matcher. For details, see
+// https://github.com/google/googletest/blob/644319b9f06f6ca9bf69fe791be399061044bc3d/googlemock/docs/CookBook.md#writing-new-polymorphic-matchers
+class IsJsonMatcher {
+ public:
+ explicit IsJsonMatcher(base::StringPiece json);
+ explicit IsJsonMatcher(const base::Value& value);
+ IsJsonMatcher(const IsJsonMatcher& other);
+ ~IsJsonMatcher();
+
+ bool MatchAndExplain(base::StringPiece json,
+ testing::MatchResultListener* listener) const;
+ bool MatchAndExplain(const base::Value& value,
+ testing::MatchResultListener* listener) const;
+ void DescribeTo(std::ostream* os) const;
+ void DescribeNegationTo(std::ostream* os) const;
+
+ private:
+ IsJsonMatcher& operator=(const IsJsonMatcher& other) = delete;
+
+ base::Value expected_value_;
+};
+
+// Creates a GMock matcher for testing equivalence of JSON values represented as
+// either JSON strings or base::Value objects. Parsing of the expected value
+// uses ParseJson(), which allows trailing commas for convenience. Parsing of
+// the actual value follows the JSON spec strictly.
+//
+// Although it possible to use this matcher when the actual and expected values
+// are both base::Value objects, there is no advantage in that case to using
+// this matcher in place of GMock's normal equality semantics.
+template <typename T>
+inline testing::PolymorphicMatcher<IsJsonMatcher> IsJson(const T& value) {
+ return testing::MakePolymorphicMatcher(IsJsonMatcher(value));
+}
+
+// Parses |json| as JSON, allowing trailing commas, and returns the resulting
+// value. If |json| fails to parse, causes an EXPECT failure and returns the
+// Null Value.
+Value ParseJson(StringPiece json);
+
+// DEPRECATED.
+// Parses |json| as JSON, allowing trailing commas, and returns the
+// resulting value. If the json fails to parse, causes an EXPECT
+// failure and returns the Null Value (but never a NULL pointer).
+std::unique_ptr<Value> ParseJsonDeprecated(StringPiece json);
+
+} // namespace test
+} // namespace base
+
+#endif // BASE_TEST_VALUES_TEST_UTIL_H_
diff --git a/chromium/base/test/with_feature_override.cc b/chromium/base/test/with_feature_override.cc
new file mode 100644
index 00000000000..7a9d78705ab
--- /dev/null
+++ b/chromium/base/test/with_feature_override.cc
@@ -0,0 +1,32 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/with_feature_override.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
+
+namespace base {
+namespace test {
+
+WithFeatureOverride::WithFeatureOverride(const base::Feature& feature) {
+ // Most other classes that tests inherit from start task environments. Verify
+ // that has not happened yet.
+ DCHECK(base::ThreadPoolInstance::Get() == nullptr)
+ << "WithFeatureOverride should be the first class a test inherits from "
+ "so it sets the features before any other setup is done.";
+
+ if (GetParam()) {
+ scoped_feature_list_.InitAndEnableFeature(feature);
+ } else {
+ scoped_feature_list_.InitAndDisableFeature(feature);
+ }
+}
+
+bool WithFeatureOverride::IsParamFeatureEnabled() {
+ return GetParam();
+}
+
+WithFeatureOverride::~WithFeatureOverride() = default;
+
+} // namespace test
+} // namespace base
diff --git a/chromium/base/test/with_feature_override.h b/chromium/base/test/with_feature_override.h
new file mode 100644
index 00000000000..9a88253c30c
--- /dev/null
+++ b/chromium/base/test/with_feature_override.h
@@ -0,0 +1,55 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_WITH_FEATURE_OVERRIDE_H_
+#define BASE_TEST_WITH_FEATURE_OVERRIDE_H_
+
+#include "base/feature_list.h"
+#include "base/macros.h"
+#include "base/test/scoped_feature_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace test {
+
+#define INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(test_name) \
+ INSTANTIATE_TEST_SUITE_P(All, test_name, testing::Values(false, true))
+
+// Base class for a test fixture that must run with a feature enabled and
+// disabled. Must be the first base class of the test fixture to take effect
+// during the construction of the test fixture itself.
+//
+// Example usage:
+//
+// class MyTest : public base::WithFeatureOverride, public testing::Test {
+// public:
+// MyTest() : WithFeatureOverride(kMyFeature){}
+// };
+//
+// TEST_P(MyTest, FooBar) {
+// This will run with both the kMyFeature enabled and disabled.
+// }
+//
+// INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(MyTest);
+
+class WithFeatureOverride : public testing::WithParamInterface<bool> {
+ public:
+ explicit WithFeatureOverride(const base::Feature& feature);
+ ~WithFeatureOverride();
+
+ WithFeatureOverride(const WithFeatureOverride&) = delete;
+ WithFeatureOverride& operator=(const WithFeatureOverride&) = delete;
+
+ // Use to know if the configured feature provided in the ctor is enabled or
+ // not.
+ bool IsParamFeatureEnabled();
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+} // namespace test
+} // namespace base
+
+#endif // BASE_TEST_WITH_FEATURE_OVERRIDE_H_